11df80918ae7b818e0f8abb1b442d7e93c6c11f70Cédric Beustpackage org.testng.reporters;
21df80918ae7b818e0f8abb1b442d7e93c6c11f70Cédric Beust
31df80918ae7b818e0f8abb1b442d7e93c6c11f70Cédric Beustimport org.testng.IReporter;
41df80918ae7b818e0f8abb1b442d7e93c6c11f70Cédric Beustimport org.testng.ISuite;
51df80918ae7b818e0f8abb1b442d7e93c6c11f70Cédric Beustimport org.testng.ISuiteResult;
61df80918ae7b818e0f8abb1b442d7e93c6c11f70Cédric Beustimport org.testng.ITestContext;
788fa06c942367a6da8b72c1c412e911924d56dc6Cédric Beustimport org.testng.ITestNGMethod;
81df80918ae7b818e0f8abb1b442d7e93c6c11f70Cédric Beustimport org.testng.ITestResult;
988fa06c942367a6da8b72c1c412e911924d56dc6Cédric Beustimport org.testng.collections.ListMultiMap;
101df80918ae7b818e0f8abb1b442d7e93c6c11f70Cédric Beustimport org.testng.collections.Lists;
111df80918ae7b818e0f8abb1b442d7e93c6c11f70Cédric Beustimport org.testng.collections.Maps;
12e9a829e47a3f321807f9f3b6a15ec98ab6e22b98Julien Herrimport org.testng.collections.Sets;
131df80918ae7b818e0f8abb1b442d7e93c6c11f70Cédric Beustimport org.testng.internal.Utils;
141df80918ae7b818e0f8abb1b442d7e93c6c11f70Cédric Beustimport org.testng.xml.XmlSuite;
151df80918ae7b818e0f8abb1b442d7e93c6c11f70Cédric Beust
1606adacf0626ec131a81c342d2787bb5019ff5669Cédric Beustimport java.io.File;
17ac22b08f9aca9ce90e075fcefe596b6694e857acCédric Beustimport java.io.PrintWriter;
18ac22b08f9aca9ce90e075fcefe596b6694e857acCédric Beustimport java.io.StringWriter;
191df80918ae7b818e0f8abb1b442d7e93c6c11f70Cédric Beustimport java.net.InetAddress;
201df80918ae7b818e0f8abb1b442d7e93c6c11f70Cédric Beustimport java.net.UnknownHostException;
2143b1fdf02721d6dc7ea4a887c4969d21d2962729Cédric Beustimport java.text.DecimalFormat;
22fe181fcce90929803be3d5a833fc4e6703f5180cCédric Beustimport java.text.DecimalFormatSymbols;
231df80918ae7b818e0f8abb1b442d7e93c6c11f70Cédric Beustimport java.util.Calendar;
241df80918ae7b818e0f8abb1b442d7e93c6c11f70Cédric Beustimport java.util.Date;
251df80918ae7b818e0f8abb1b442d7e93c6c11f70Cédric Beustimport java.util.List;
261df80918ae7b818e0f8abb1b442d7e93c6c11f70Cédric Beustimport java.util.Map;
271df80918ae7b818e0f8abb1b442d7e93c6c11f70Cédric Beustimport java.util.Properties;
281df80918ae7b818e0f8abb1b442d7e93c6c11f70Cédric Beustimport java.util.Set;
291df80918ae7b818e0f8abb1b442d7e93c6c11f70Cédric Beust
301df80918ae7b818e0f8abb1b442d7e93c6c11f70Cédric Beustpublic class JUnitReportReporter implements IReporter {
311df80918ae7b818e0f8abb1b442d7e93c6c11f70Cédric Beust
321df80918ae7b818e0f8abb1b442d7e93c6c11f70Cédric Beust  @Override
331df80918ae7b818e0f8abb1b442d7e93c6c11f70Cédric Beust  public void generateReport(List<XmlSuite> xmlSuites, List<ISuite> suites,
3406adacf0626ec131a81c342d2787bb5019ff5669Cédric Beust      String defaultOutputDirectory) {
351df80918ae7b818e0f8abb1b442d7e93c6c11f70Cédric Beust
361df80918ae7b818e0f8abb1b442d7e93c6c11f70Cédric Beust    Map<Class<?>, Set<ITestResult>> results = Maps.newHashMap();
373c331730b067c4367825ba373dbcf0be02df6fe5Cédric Beust    Map<Class<?>, Set<ITestResult>> failedConfigurations = Maps.newHashMap();
38d1f454d6b983329674a0a6090432ed6a30dd6b15Cédric Beust    ListMultiMap<Object, ITestResult> befores = Maps.newListMultiMap();
39d1f454d6b983329674a0a6090432ed6a30dd6b15Cédric Beust    ListMultiMap<Object, ITestResult> afters = Maps.newListMultiMap();
401df80918ae7b818e0f8abb1b442d7e93c6c11f70Cédric Beust    for (ISuite suite : suites) {
411df80918ae7b818e0f8abb1b442d7e93c6c11f70Cédric Beust      Map<String, ISuiteResult> suiteResults = suite.getResults();
421df80918ae7b818e0f8abb1b442d7e93c6c11f70Cédric Beust      for (ISuiteResult sr : suiteResults.values()) {
431df80918ae7b818e0f8abb1b442d7e93c6c11f70Cédric Beust        ITestContext tc = sr.getTestContext();
441df80918ae7b818e0f8abb1b442d7e93c6c11f70Cédric Beust        addResults(tc.getPassedTests().getAllResults(), results);
451df80918ae7b818e0f8abb1b442d7e93c6c11f70Cédric Beust        addResults(tc.getFailedTests().getAllResults(), results);
461df80918ae7b818e0f8abb1b442d7e93c6c11f70Cédric Beust        addResults(tc.getSkippedTests().getAllResults(), results);
473c331730b067c4367825ba373dbcf0be02df6fe5Cédric Beust        addResults(tc.getFailedConfigurations().getAllResults(), failedConfigurations);
48d1f454d6b983329674a0a6090432ed6a30dd6b15Cédric Beust        for (ITestResult tr : tc.getPassedConfigurations().getAllResults()) {
49d1f454d6b983329674a0a6090432ed6a30dd6b15Cédric Beust          if (tr.getMethod().isBeforeMethodConfiguration()) {
50d1f454d6b983329674a0a6090432ed6a30dd6b15Cédric Beust            befores.put(tr.getInstance(), tr);
51d1f454d6b983329674a0a6090432ed6a30dd6b15Cédric Beust          }
52d1f454d6b983329674a0a6090432ed6a30dd6b15Cédric Beust          if (tr.getMethod().isAfterMethodConfiguration()) {
53d1f454d6b983329674a0a6090432ed6a30dd6b15Cédric Beust            afters.put(tr.getInstance(), tr);
54d1f454d6b983329674a0a6090432ed6a30dd6b15Cédric Beust          }
55d1f454d6b983329674a0a6090432ed6a30dd6b15Cédric Beust        }
561df80918ae7b818e0f8abb1b442d7e93c6c11f70Cédric Beust      }
571df80918ae7b818e0f8abb1b442d7e93c6c11f70Cédric Beust    }
581df80918ae7b818e0f8abb1b442d7e93c6c11f70Cédric Beust
59f3b258ee71205a817448da589b2bf43ec4db8f1bCédric Beust    // A list of iterators for all the passed configuration, explanation below
60d1f454d6b983329674a0a6090432ed6a30dd6b15Cédric Beust//    ListMultiMap<Class<?>, ITestResult> beforeConfigurations = Maps.newListMultiMap();
61d1f454d6b983329674a0a6090432ed6a30dd6b15Cédric Beust//    ListMultiMap<Class<?>, ITestResult> afterConfigurations = Maps.newListMultiMap();
62d1f454d6b983329674a0a6090432ed6a30dd6b15Cédric Beust//    for (Map.Entry<Class<?>, Set<ITestResult>> es : passedConfigurations.entrySet()) {
63d1f454d6b983329674a0a6090432ed6a30dd6b15Cédric Beust//      for (ITestResult tr : es.getValue()) {
64d1f454d6b983329674a0a6090432ed6a30dd6b15Cédric Beust//        ITestNGMethod method = tr.getMethod();
65d1f454d6b983329674a0a6090432ed6a30dd6b15Cédric Beust//        if (method.isBeforeMethodConfiguration()) {
66d1f454d6b983329674a0a6090432ed6a30dd6b15Cédric Beust//          beforeConfigurations.put(method.getRealClass(), tr);
67d1f454d6b983329674a0a6090432ed6a30dd6b15Cédric Beust//        }
68d1f454d6b983329674a0a6090432ed6a30dd6b15Cédric Beust//        if (method.isAfterMethodConfiguration()) {
69d1f454d6b983329674a0a6090432ed6a30dd6b15Cédric Beust//          afterConfigurations.put(method.getRealClass(), tr);
70d1f454d6b983329674a0a6090432ed6a30dd6b15Cédric Beust//        }
71d1f454d6b983329674a0a6090432ed6a30dd6b15Cédric Beust//      }
72d1f454d6b983329674a0a6090432ed6a30dd6b15Cédric Beust//    }
73d1f454d6b983329674a0a6090432ed6a30dd6b15Cédric Beust//    Map<Object, Iterator<ITestResult>> befores = Maps.newHashMap();
74d1f454d6b983329674a0a6090432ed6a30dd6b15Cédric Beust//    for (Map.Entry<Class<?>, List<ITestResult>> es : beforeConfigurations.getEntrySet()) {
75d1f454d6b983329674a0a6090432ed6a30dd6b15Cédric Beust//      List<ITestResult> tr = es.getValue();
76d1f454d6b983329674a0a6090432ed6a30dd6b15Cédric Beust//      for (ITestResult itr : es.getValue()) {
77d1f454d6b983329674a0a6090432ed6a30dd6b15Cédric Beust//      }
78d1f454d6b983329674a0a6090432ed6a30dd6b15Cédric Beust//    }
79d1f454d6b983329674a0a6090432ed6a30dd6b15Cédric Beust//    Map<Class<?>, Iterator<ITestResult>> afters = Maps.newHashMap();
80d1f454d6b983329674a0a6090432ed6a30dd6b15Cédric Beust//    for (Map.Entry<Class<?>, List<ITestResult>> es : afterConfigurations.getEntrySet()) {
81d1f454d6b983329674a0a6090432ed6a30dd6b15Cédric Beust//      afters.put(es.getKey(), es.getValue().iterator());
82d1f454d6b983329674a0a6090432ed6a30dd6b15Cédric Beust//    }
83f3b258ee71205a817448da589b2bf43ec4db8f1bCédric Beust
841df80918ae7b818e0f8abb1b442d7e93c6c11f70Cédric Beust    for (Map.Entry<Class<?>, Set<ITestResult>> entry : results.entrySet()) {
851df80918ae7b818e0f8abb1b442d7e93c6c11f70Cédric Beust      Class<?> cls = entry.getKey();
861df80918ae7b818e0f8abb1b442d7e93c6c11f70Cédric Beust      Properties p1 = new Properties();
871df80918ae7b818e0f8abb1b442d7e93c6c11f70Cédric Beust      p1.setProperty("name", cls.getName());
881df80918ae7b818e0f8abb1b442d7e93c6c11f70Cédric Beust      Date timeStamp = Calendar.getInstance().getTime();
896528aa29713294f6126ebec9ee41ba81bf991517Testo Nakada      p1.setProperty(XMLConstants.ATTR_TIMESTAMP, timeStamp.toGMTString());
901df80918ae7b818e0f8abb1b442d7e93c6c11f70Cédric Beust
91ac22b08f9aca9ce90e075fcefe596b6694e857acCédric Beust      List<TestTag> testCases = Lists.newArrayList();
921df80918ae7b818e0f8abb1b442d7e93c6c11f70Cédric Beust      int failures = 0;
93ac22b08f9aca9ce90e075fcefe596b6694e857acCédric Beust      int errors = 0;
947a4393234fa0020e2137fd82f7d23e77d8e26300Cédric Beust      int testCount = 0;
9543b1fdf02721d6dc7ea4a887c4969d21d2962729Cédric Beust      float totalTime = 0;
961df80918ae7b818e0f8abb1b442d7e93c6c11f70Cédric Beust
971df80918ae7b818e0f8abb1b442d7e93c6c11f70Cédric Beust      for (ITestResult tr: entry.getValue()) {
98ac22b08f9aca9ce90e075fcefe596b6694e857acCédric Beust        TestTag testTag = new TestTag();
99ac22b08f9aca9ce90e075fcefe596b6694e857acCédric Beust
100df7b7b627f7adc28d415d7cd1cbe54a1815c81c6Cédric Beust        boolean isSuccess = tr.getStatus() == ITestResult.SUCCESS;
101efbb5bfaa8b617f81bea3b994a36ceb66a66ac3fCédric Beust        if (! isSuccess) {
102df7b7b627f7adc28d415d7cd1cbe54a1815c81c6Cédric Beust          if (tr.getThrowable() instanceof AssertionError) {
1030f7e671c94aeedee2fbc796b3318d44b0297b6cdnullin            failures++;
104befbe5675477df9f0953a09e2657c76b1387184cjerome-jacob          } else {
105befbe5675477df9f0953a09e2657c76b1387184cjerome-jacob            errors++;
1060f7e671c94aeedee2fbc796b3318d44b0297b6cdnullin          }
107a7b40000a3ed4fd822be3aeba465833bacb2d7aeCédric Beust        }
108df7b7b627f7adc28d415d7cd1cbe54a1815c81c6Cédric Beust
1091df80918ae7b818e0f8abb1b442d7e93c6c11f70Cédric Beust        Properties p2 = new Properties();
110bef5a1ed1964aaa626a1134ae80519fcc5f21f2fCédric Beust        p2.setProperty("classname", cls.getName());
111270481fb103191df4a89a6b4323ac2aecece440eCédric Beust        p2.setProperty("name", getTestName(tr));
1127a4393234fa0020e2137fd82f7d23e77d8e26300Cédric Beust        long time = tr.getEndMillis() - tr.getStartMillis();
113f3b258ee71205a817448da589b2bf43ec4db8f1bCédric Beust
11488fa06c942367a6da8b72c1c412e911924d56dc6Cédric Beust        time += getNextConfiguration(befores, tr);
11588fa06c942367a6da8b72c1c412e911924d56dc6Cédric Beust        time += getNextConfiguration(afters, tr);
116f3b258ee71205a817448da589b2bf43ec4db8f1bCédric Beust
117e99ce2c6cffa9c9c4271fe5c487b98b69689eb5cCédric Beust        p2.setProperty("time", "" + formatTime(time));
1183c331730b067c4367825ba373dbcf0be02df6fe5Cédric Beust        Throwable t = getThrowable(tr, failedConfigurations);
119df7b7b627f7adc28d415d7cd1cbe54a1815c81c6Cédric Beust        if (! isSuccess && t != null) {
120ac22b08f9aca9ce90e075fcefe596b6694e857acCédric Beust          StringWriter sw = new StringWriter();
121ac22b08f9aca9ce90e075fcefe596b6694e857acCédric Beust          PrintWriter pw = new PrintWriter(sw);
122ac22b08f9aca9ce90e075fcefe596b6694e857acCédric Beust          t.printStackTrace(pw);
123ac22b08f9aca9ce90e075fcefe596b6694e857acCédric Beust          testTag.message = t.getMessage();
124ac22b08f9aca9ce90e075fcefe596b6694e857acCédric Beust          testTag.type = t.getClass().getName();
125ac22b08f9aca9ce90e075fcefe596b6694e857acCédric Beust          testTag.stackTrace = sw.toString();
126befbe5675477df9f0953a09e2657c76b1387184cjerome-jacob          testTag.errorTag = tr.getThrowable() instanceof AssertionError ? "failure" : "error";
127ac22b08f9aca9ce90e075fcefe596b6694e857acCédric Beust        }
1287a4393234fa0020e2137fd82f7d23e77d8e26300Cédric Beust        totalTime += time;
1297a4393234fa0020e2137fd82f7d23e77d8e26300Cédric Beust        testCount++;
130ac22b08f9aca9ce90e075fcefe596b6694e857acCédric Beust        testTag.properties = p2;
131ac22b08f9aca9ce90e075fcefe596b6694e857acCédric Beust        testCases.add(testTag);
1321df80918ae7b818e0f8abb1b442d7e93c6c11f70Cédric Beust      }
1331df80918ae7b818e0f8abb1b442d7e93c6c11f70Cédric Beust
1341df80918ae7b818e0f8abb1b442d7e93c6c11f70Cédric Beust      p1.setProperty("failures", "" + failures);
135ac22b08f9aca9ce90e075fcefe596b6694e857acCédric Beust      p1.setProperty("errors", "" + errors);
1361df80918ae7b818e0f8abb1b442d7e93c6c11f70Cédric Beust      p1.setProperty("name", cls.getName());
1377a4393234fa0020e2137fd82f7d23e77d8e26300Cédric Beust      p1.setProperty("tests", "" + testCount);
138e99ce2c6cffa9c9c4271fe5c487b98b69689eb5cCédric Beust      p1.setProperty("time", "" + formatTime(totalTime));
1391df80918ae7b818e0f8abb1b442d7e93c6c11f70Cédric Beust      try {
1401df80918ae7b818e0f8abb1b442d7e93c6c11f70Cédric Beust        p1.setProperty(XMLConstants.ATTR_HOSTNAME, InetAddress.getLocalHost().getHostName());
1411df80918ae7b818e0f8abb1b442d7e93c6c11f70Cédric Beust      } catch (UnknownHostException e) {
1421df80918ae7b818e0f8abb1b442d7e93c6c11f70Cédric Beust        // ignore
1431df80918ae7b818e0f8abb1b442d7e93c6c11f70Cédric Beust      }
1441df80918ae7b818e0f8abb1b442d7e93c6c11f70Cédric Beust
1451df80918ae7b818e0f8abb1b442d7e93c6c11f70Cédric Beust      //
1461df80918ae7b818e0f8abb1b442d7e93c6c11f70Cédric Beust      // Now that we have all the information we need, generate the file
1471df80918ae7b818e0f8abb1b442d7e93c6c11f70Cédric Beust      //
1488d01b98cf847fce5699f8e8afe6d2a25c85c5435Cédric Beust      XMLStringBuffer xsb = new XMLStringBuffer();
14906adacf0626ec131a81c342d2787bb5019ff5669Cédric Beust      xsb.addComment("Generated by " + getClass().getName());
15006adacf0626ec131a81c342d2787bb5019ff5669Cédric Beust
1511df80918ae7b818e0f8abb1b442d7e93c6c11f70Cédric Beust      xsb.push("testsuite", p1);
152ac22b08f9aca9ce90e075fcefe596b6694e857acCédric Beust      for (TestTag testTag : testCases) {
1530f7e671c94aeedee2fbc796b3318d44b0297b6cdnullin        if (testTag.stackTrace == null) {
1540f7e671c94aeedee2fbc796b3318d44b0297b6cdnullin          xsb.addEmptyElement("testcase", testTag.properties);
155bef5a1ed1964aaa626a1134ae80519fcc5f21f2fCédric Beust        }
156ac22b08f9aca9ce90e075fcefe596b6694e857acCédric Beust        else {
157ac22b08f9aca9ce90e075fcefe596b6694e857acCédric Beust          xsb.push("testcase", testTag.properties);
158ac22b08f9aca9ce90e075fcefe596b6694e857acCédric Beust
159ac22b08f9aca9ce90e075fcefe596b6694e857acCédric Beust          Properties p = new Properties();
1600f7e671c94aeedee2fbc796b3318d44b0297b6cdnullin          if (testTag.message != null) {
1610f7e671c94aeedee2fbc796b3318d44b0297b6cdnullin            p.setProperty("message", testTag.message);
1620f7e671c94aeedee2fbc796b3318d44b0297b6cdnullin          }
163ac22b08f9aca9ce90e075fcefe596b6694e857acCédric Beust          p.setProperty("type", testTag.type);
164a7b40000a3ed4fd822be3aeba465833bacb2d7aeCédric Beust          xsb.push(testTag.errorTag, p);
165ac22b08f9aca9ce90e075fcefe596b6694e857acCédric Beust          xsb.addCDATA(testTag.stackTrace);
166a7b40000a3ed4fd822be3aeba465833bacb2d7aeCédric Beust          xsb.pop(testTag.errorTag);
167ac22b08f9aca9ce90e075fcefe596b6694e857acCédric Beust
168ac22b08f9aca9ce90e075fcefe596b6694e857acCédric Beust          xsb.pop("testcase");
169ac22b08f9aca9ce90e075fcefe596b6694e857acCédric Beust        }
1701df80918ae7b818e0f8abb1b442d7e93c6c11f70Cédric Beust      }
1711df80918ae7b818e0f8abb1b442d7e93c6c11f70Cédric Beust      xsb.pop("testsuite");
17206adacf0626ec131a81c342d2787bb5019ff5669Cédric Beust
173270481fb103191df4a89a6b4323ac2aecece440eCédric Beust      String outputDirectory = defaultOutputDirectory + File.separator + "junitreports";
1744f2b7e50f1b3284d17f6368b3cf59b88fe70a675Cédric Beust      Utils.writeUtf8File(outputDirectory, getFileName(cls), xsb.toXML());
1751df80918ae7b818e0f8abb1b442d7e93c6c11f70Cédric Beust    }
1761df80918ae7b818e0f8abb1b442d7e93c6c11f70Cédric Beust
1771df80918ae7b818e0f8abb1b442d7e93c6c11f70Cédric Beust//    System.out.println(xsb.toXML());
1781df80918ae7b818e0f8abb1b442d7e93c6c11f70Cédric Beust//    System.out.println("");
1791df80918ae7b818e0f8abb1b442d7e93c6c11f70Cédric Beust
1801df80918ae7b818e0f8abb1b442d7e93c6c11f70Cédric Beust  }
1811df80918ae7b818e0f8abb1b442d7e93c6c11f70Cédric Beust
18288fa06c942367a6da8b72c1c412e911924d56dc6Cédric Beust  /**
183d1f454d6b983329674a0a6090432ed6a30dd6b15Cédric Beust   * Add the time of the configuration method to this test method.
18488fa06c942367a6da8b72c1c412e911924d56dc6Cédric Beust   *
18588fa06c942367a6da8b72c1c412e911924d56dc6Cédric Beust   * The only problem with this method is that the timing of a test method
186d1f454d6b983329674a0a6090432ed6a30dd6b15Cédric Beust   * might not be added to the time of the same configuration method that ran before
187d1f454d6b983329674a0a6090432ed6a30dd6b15Cédric Beust   * it but since they should all be equivalent, this should never be an issue.
18888fa06c942367a6da8b72c1c412e911924d56dc6Cédric Beust   */
189d1f454d6b983329674a0a6090432ed6a30dd6b15Cédric Beust  private long getNextConfiguration(ListMultiMap<Object, ITestResult> configurations,
19088fa06c942367a6da8b72c1c412e911924d56dc6Cédric Beust      ITestResult tr)
19188fa06c942367a6da8b72c1c412e911924d56dc6Cédric Beust  {
19288fa06c942367a6da8b72c1c412e911924d56dc6Cédric Beust    long result = 0;
19388fa06c942367a6da8b72c1c412e911924d56dc6Cédric Beust
194d1f454d6b983329674a0a6090432ed6a30dd6b15Cédric Beust    List<ITestResult> confResults = configurations.get(tr.getInstance());
195d1f454d6b983329674a0a6090432ed6a30dd6b15Cédric Beust    Map<ITestNGMethod, ITestResult> seen = Maps.newHashMap();
196d1f454d6b983329674a0a6090432ed6a30dd6b15Cédric Beust    if (confResults != null) {
197d1f454d6b983329674a0a6090432ed6a30dd6b15Cédric Beust      for (ITestResult r : confResults) {
198d1f454d6b983329674a0a6090432ed6a30dd6b15Cédric Beust        if (! seen.containsKey(r.getMethod())) {
199d1f454d6b983329674a0a6090432ed6a30dd6b15Cédric Beust          result += r.getEndMillis() - r.getStartMillis();
200d1f454d6b983329674a0a6090432ed6a30dd6b15Cédric Beust          seen.put(r.getMethod(), r);
201d1f454d6b983329674a0a6090432ed6a30dd6b15Cédric Beust        }
202d1f454d6b983329674a0a6090432ed6a30dd6b15Cédric Beust      }
203d1f454d6b983329674a0a6090432ed6a30dd6b15Cédric Beust      confResults.removeAll(seen.values());
20488fa06c942367a6da8b72c1c412e911924d56dc6Cédric Beust    }
20588fa06c942367a6da8b72c1c412e911924d56dc6Cédric Beust
20688fa06c942367a6da8b72c1c412e911924d56dc6Cédric Beust    return result;
20788fa06c942367a6da8b72c1c412e911924d56dc6Cédric Beust  }
20888fa06c942367a6da8b72c1c412e911924d56dc6Cédric Beust
209270481fb103191df4a89a6b4323ac2aecece440eCédric Beust  protected String getFileName(Class cls) {
210270481fb103191df4a89a6b4323ac2aecece440eCédric Beust    return "TEST-" + cls.getName() + ".xml";
211270481fb103191df4a89a6b4323ac2aecece440eCédric Beust  }
212270481fb103191df4a89a6b4323ac2aecece440eCédric Beust
213270481fb103191df4a89a6b4323ac2aecece440eCédric Beust  protected String getTestName(ITestResult tr) {
214270481fb103191df4a89a6b4323ac2aecece440eCédric Beust    return tr.getMethod().getMethodName();
215270481fb103191df4a89a6b4323ac2aecece440eCédric Beust  }
216270481fb103191df4a89a6b4323ac2aecece440eCédric Beust
217e99ce2c6cffa9c9c4271fe5c487b98b69689eb5cCédric Beust  private String formatTime(float time) {
218fe181fcce90929803be3d5a833fc4e6703f5180cCédric Beust    DecimalFormatSymbols symbols = new DecimalFormatSymbols();
219fe181fcce90929803be3d5a833fc4e6703f5180cCédric Beust    // JUnitReports wants points here, regardless of the locale
220fe181fcce90929803be3d5a833fc4e6703f5180cCédric Beust    symbols.setDecimalSeparator('.');
221fe181fcce90929803be3d5a833fc4e6703f5180cCédric Beust    DecimalFormat format = new DecimalFormat("#.###", symbols);
222e99ce2c6cffa9c9c4271fe5c487b98b69689eb5cCédric Beust    format.setMinimumFractionDigits(3);
223e99ce2c6cffa9c9c4271fe5c487b98b69689eb5cCédric Beust    return format.format(time / 1000.0f);
224e99ce2c6cffa9c9c4271fe5c487b98b69689eb5cCédric Beust  }
225e99ce2c6cffa9c9c4271fe5c487b98b69689eb5cCédric Beust
2263c331730b067c4367825ba373dbcf0be02df6fe5Cédric Beust  private Throwable getThrowable(ITestResult tr,
2273c331730b067c4367825ba373dbcf0be02df6fe5Cédric Beust      Map<Class<?>, Set<ITestResult>> failedConfigurations) {
2283c331730b067c4367825ba373dbcf0be02df6fe5Cédric Beust    Throwable result = tr.getThrowable();
2293c331730b067c4367825ba373dbcf0be02df6fe5Cédric Beust    if (result == null && tr.getStatus() == ITestResult.SKIP) {
2303c331730b067c4367825ba373dbcf0be02df6fe5Cédric Beust      // Attempt to grab the stack trace from the configuration failure
2313c331730b067c4367825ba373dbcf0be02df6fe5Cédric Beust      for (Set<ITestResult> failures : failedConfigurations.values()) {
2323c331730b067c4367825ba373dbcf0be02df6fe5Cédric Beust        for (ITestResult failure : failures) {
2333c331730b067c4367825ba373dbcf0be02df6fe5Cédric Beust          // Naive implementation for now, eventually, we need to try to find
2343c331730b067c4367825ba373dbcf0be02df6fe5Cédric Beust          // out if it's this failure that caused the skip since (maybe by
2353c331730b067c4367825ba373dbcf0be02df6fe5Cédric Beust          // seeing if the class of the configuration method is assignable to
2363c331730b067c4367825ba373dbcf0be02df6fe5Cédric Beust          // the class of the test method, although that's not 100% fool proof
2370f7e671c94aeedee2fbc796b3318d44b0297b6cdnullin          if (failure.getThrowable() != null) {
2380f7e671c94aeedee2fbc796b3318d44b0297b6cdnullin            return failure.getThrowable();
2390f7e671c94aeedee2fbc796b3318d44b0297b6cdnullin          }
2403c331730b067c4367825ba373dbcf0be02df6fe5Cédric Beust        }
2413c331730b067c4367825ba373dbcf0be02df6fe5Cédric Beust      }
2423c331730b067c4367825ba373dbcf0be02df6fe5Cédric Beust    }
2433c331730b067c4367825ba373dbcf0be02df6fe5Cédric Beust
2443c331730b067c4367825ba373dbcf0be02df6fe5Cédric Beust    return result;
2453c331730b067c4367825ba373dbcf0be02df6fe5Cédric Beust  }
2463c331730b067c4367825ba373dbcf0be02df6fe5Cédric Beust
2476e714088ed5ccb46e3f204b5048c7527729e38cdTesto Nakada  static class TestTag {
248ac22b08f9aca9ce90e075fcefe596b6694e857acCédric Beust    public Properties properties;
249ac22b08f9aca9ce90e075fcefe596b6694e857acCédric Beust    public String message;
250ac22b08f9aca9ce90e075fcefe596b6694e857acCédric Beust    public String type;
251ac22b08f9aca9ce90e075fcefe596b6694e857acCédric Beust    public String stackTrace;
252a7b40000a3ed4fd822be3aeba465833bacb2d7aeCédric Beust    public String errorTag;
253ac22b08f9aca9ce90e075fcefe596b6694e857acCédric Beust  }
254ac22b08f9aca9ce90e075fcefe596b6694e857acCédric Beust
2551df80918ae7b818e0f8abb1b442d7e93c6c11f70Cédric Beust  private void addResults(Set<ITestResult> allResults, Map<Class<?>, Set<ITestResult>> out) {
2561df80918ae7b818e0f8abb1b442d7e93c6c11f70Cédric Beust    for (ITestResult tr : allResults) {
257ac22b08f9aca9ce90e075fcefe596b6694e857acCédric Beust      Class<?> cls = tr.getMethod().getTestClass().getRealClass();
2581df80918ae7b818e0f8abb1b442d7e93c6c11f70Cédric Beust      Set<ITestResult> l = out.get(cls);
2591df80918ae7b818e0f8abb1b442d7e93c6c11f70Cédric Beust      if (l == null) {
2601df80918ae7b818e0f8abb1b442d7e93c6c11f70Cédric Beust        l = Sets.newHashSet();
2611df80918ae7b818e0f8abb1b442d7e93c6c11f70Cédric Beust        out.put(cls, l);
2621df80918ae7b818e0f8abb1b442d7e93c6c11f70Cédric Beust      }
2631df80918ae7b818e0f8abb1b442d7e93c6c11f70Cédric Beust      l.add(tr);
2641df80918ae7b818e0f8abb1b442d7e93c6c11f70Cédric Beust    }
2651df80918ae7b818e0f8abb1b442d7e93c6c11f70Cédric Beust  }
2661df80918ae7b818e0f8abb1b442d7e93c6c11f70Cédric Beust
2671df80918ae7b818e0f8abb1b442d7e93c6c11f70Cédric Beust}
268