View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *   http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  package org.apache.maven.plugins.surefire.report;
20  
21  import java.io.*;
22  import java.nio.file.Files;
23  import java.nio.file.Path;
24  import java.util.ArrayList;
25  import java.util.Collection;
26  import java.util.List;
27  
28  import org.apache.maven.plugin.surefire.log.api.ConsoleLogger;
29  import org.apache.maven.plugins.surefire.report.ReportTestCase.FlakyError;
30  import org.apache.maven.plugins.surefire.report.ReportTestCase.FlakyFailure;
31  import org.junit.After;
32  import org.junit.Before;
33  import org.junit.Test;
34  
35  import static java.nio.charset.StandardCharsets.UTF_8;
36  import static org.hamcrest.MatcherAssert.assertThat;
37  import static org.hamcrest.Matchers.containsString;
38  import static org.hamcrest.Matchers.empty;
39  import static org.hamcrest.Matchers.is;
40  import static org.hamcrest.Matchers.startsWith;
41  import static org.junit.Assert.assertEquals;
42  import static org.junit.Assert.assertFalse;
43  import static org.junit.Assert.assertNotNull;
44  import static org.junit.Assert.assertNull;
45  import static org.junit.Assert.assertTrue;
46  import static org.junit.Assume.assumeTrue;
47  
48  /**
49   * @author Kristian Rosenvold
50   */
51  @SuppressWarnings({"checkstyle:magicnumber", "checkstyle:linelength"})
52  public class TestSuiteXmlParserTest {
53      private static final String[] LINE_PATTERNS = {"at org.apache.Test.", "at org.apache.Test$"};
54  
55      private final Collection<String> loggedErrors = new ArrayList<>();
56  
57      private ConsoleLogger consoleLogger;
58  
59      @Before
60      public void instantiateLogger() {
61          consoleLogger = new ConsoleLogger() {
62              @Override
63              public boolean isDebugEnabled() {
64                  return true;
65              }
66  
67              @Override
68              public void debug(String message) {}
69  
70              @Override
71              public boolean isInfoEnabled() {
72                  return true;
73              }
74  
75              @Override
76              public void info(String message) {}
77  
78              @Override
79              public boolean isWarnEnabled() {
80                  return true;
81              }
82  
83              @Override
84              public void warning(String message) {
85                  loggedErrors.add(message);
86              }
87  
88              @Override
89              public boolean isErrorEnabled() {
90                  return true;
91              }
92  
93              @Override
94              public void error(String message) {
95                  loggedErrors.add(message);
96              }
97  
98              @Override
99              public void error(String message, Throwable t) {
100                 loggedErrors.add(message);
101             }
102 
103             @Override
104             public void error(Throwable t) {
105                 loggedErrors.add(t.getLocalizedMessage());
106             }
107         };
108     }
109 
110     @After
111     public void verifyErrorFreeLogger() {
112         assertThat(loggedErrors, is(empty()));
113     }
114 
115     @Test
116     public void testParse() throws Exception {
117         TestSuiteXmlParser testSuiteXmlParser = new TestSuiteXmlParser(consoleLogger);
118         String xml = "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n"
119                 + "<testsuite failures=\"4\" time=\"0.00005\" errors=\"0\" skipped=\"0\" tests=\"4\" name=\"wellFormedXmlFailures.TestSurefire3\">\n"
120                 + "  <properties>\n"
121                 + "    <property name=\"java.runtime.name\" value=\"Java(TM) SE Runtime Environment\"/>\n"
122                 + "    <property name=\"sun.cpu.isalist\" value=\"amd64\"/>\n"
123                 + "  </properties>\n"
124                 + "  <testcase time=\"5E-3\" classname=\"wellFormedXmlFailures.TestSurefire3\" name=\"testLower\">\n"
125                 + "    <failure message=\"&lt;\" type=\"junit.framework.AssertionFailedError\"><![CDATA[junit.framework.AssertionFailedError: <\n"
126                 + "\tat junit.framework.Assert.fail(Assert.java:47)\n"
127                 + "\tat wellFormedXmlFailures.TestSurefire3.testLower(TestSurefire3.java:30)\n"
128                 + "]]></failure>\n"
129                 + "  </testcase>\n"
130                 + "  <testcase time=\"0\" classname=\"wellFormedXmlFailures.TestSurefire3\" name=\"testU0000\">\n"
131                 + "    <failure message=\"&amp;0#;\" type=\"junit.framework.AssertionFailedError\">junit.framework.AssertionFailedError:  \n"
132                 + "\tat junit.framework.Assert.fail(Assert.java:47)\n"
133                 + "\tat wellFormedXmlFailures.TestSurefire3.testU0000(TestSurefire3.java:40)\n"
134                 + "</failure>\n"
135                 + "  </testcase>\n"
136                 + "  <testcase time=\"0\" classname=\"wellFormedXmlFailures.TestSurefire3\" name=\"testGreater\">\n"
137                 + "    <failure message=\"&gt;\" type=\"junit.framework.AssertionFailedError\">junit.framework.AssertionFailedError: >\n"
138                 + "\tat junit.framework.Assert.fail(Assert.java:47)\n"
139                 + "\tat wellFormedXmlFailures.TestSurefire3.testGreater(TestSurefire3.java:35)\n"
140                 + "</failure>\n"
141                 + "  </testcase>\n"
142                 + "  <testcase time=\"0\" classname=\"wellFormedXmlFailures.TestSurefire3\" name=\"testQuote\">\n"
143                 + "    <failure message=\"&quot;\" type=\"junit.framework.AssertionFailedError\">junit.framework.AssertionFailedError: \"\n"
144                 + "\tat junit.framework.Assert.fail(Assert.java:47)\n"
145                 + "\tat wellFormedXmlFailures.TestSurefire3.testQuote(TestSurefire3.java:25)\n"
146                 + "</failure>\n"
147                 + "  </testcase>\n"
148                 + "</testsuite>";
149         InputStream byteArrayIs = new ByteArrayInputStream(xml.getBytes());
150         List<ReportTestSuite> parse = testSuiteXmlParser.parse(new InputStreamReader(byteArrayIs, UTF_8));
151         assertThat(parse.size(), is(1));
152         ReportTestSuite report = parse.get(0);
153         assertThat(report.getFullClassName(), is("wellFormedXmlFailures.TestSurefire3"));
154         assertThat(report.getName(), is("TestSurefire3"));
155         assertThat(report.getPackageName(), is("wellFormedXmlFailures"));
156         assertThat(report.getNumberOfTests(), is(4));
157         assertThat(report.getNumberOfSkipped(), is(0));
158         assertThat(report.getNumberOfErrors(), is(0));
159         assertThat(report.getNumberOfFailures(), is(4));
160         assertThat(report.getNumberOfFlakes(), is(0));
161         assertThat(report.getTimeElapsed(), is(0.00005f));
162         assertThat(report.getTestCases().size(), is(4));
163 
164         List<ReportTestCase> tests = report.getTestCases();
165         assertThat(tests.get(0).getFullClassName(), is("wellFormedXmlFailures.TestSurefire3"));
166         assertThat(tests.get(0).getName(), is("testLower"));
167         assertThat(
168                 tests.get(0).getFailureDetail(),
169                 is("junit.framework.AssertionFailedError: <\n"
170                         + "\tat junit.framework.Assert.fail(Assert.java:47)\n"
171                         + "\tat wellFormedXmlFailures.TestSurefire3.testLower(TestSurefire3.java:30)\n"));
172         assertThat(tests.get(0).getClassName(), is("TestSurefire3"));
173         assertThat(tests.get(0).getTime(), is(0.005f));
174         assertThat(tests.get(0).getFailureErrorLine(), is("30"));
175         assertThat(tests.get(0).getFailureMessage(), is("<"));
176         assertThat(tests.get(0).getFullName(), is("wellFormedXmlFailures.TestSurefire3.testLower"));
177         assertThat(tests.get(0).getFailureType(), is("junit.framework.AssertionFailedError"));
178         assertThat(tests.get(0).hasError(), is(false));
179 
180         assertThat(tests.get(1).getFullClassName(), is("wellFormedXmlFailures.TestSurefire3"));
181         assertThat(tests.get(1).getName(), is("testU0000"));
182         assertThat(
183                 tests.get(1).getFailureDetail(),
184                 is("junit.framework.AssertionFailedError:  \n" + "\tat junit.framework.Assert.fail(Assert.java:47)\n"
185                         + "\tat wellFormedXmlFailures.TestSurefire3.testU0000(TestSurefire3.java:40)\n"));
186         assertThat(tests.get(1).getClassName(), is("TestSurefire3"));
187         assertThat(tests.get(1).getTime(), is(0f));
188         assertThat(tests.get(1).getFailureErrorLine(), is("40"));
189         assertThat(tests.get(1).getFailureMessage(), is("&0#;"));
190         assertThat(tests.get(1).getFullName(), is("wellFormedXmlFailures.TestSurefire3.testU0000"));
191         assertThat(tests.get(1).getFailureType(), is("junit.framework.AssertionFailedError"));
192         assertThat(tests.get(1).hasError(), is(false));
193 
194         assertThat(tests.get(2).getFullClassName(), is("wellFormedXmlFailures.TestSurefire3"));
195         assertThat(tests.get(2).getName(), is("testGreater"));
196         assertThat(
197                 tests.get(2).getFailureDetail(),
198                 is("junit.framework.AssertionFailedError: >\n" + "\tat junit.framework.Assert.fail(Assert.java:47)\n"
199                         + "\tat wellFormedXmlFailures.TestSurefire3.testGreater(TestSurefire3.java:35)\n"));
200         assertThat(tests.get(2).getClassName(), is("TestSurefire3"));
201         assertThat(tests.get(2).getTime(), is(0f));
202         assertThat(tests.get(2).getFailureErrorLine(), is("35"));
203         assertThat(tests.get(2).getFailureMessage(), is(">"));
204         assertThat(tests.get(2).getFullName(), is("wellFormedXmlFailures.TestSurefire3.testGreater"));
205         assertThat(tests.get(2).getFailureType(), is("junit.framework.AssertionFailedError"));
206         assertThat(tests.get(2).hasError(), is(false));
207 
208         assertThat(tests.get(3).getFullClassName(), is("wellFormedXmlFailures.TestSurefire3"));
209         assertThat(tests.get(3).getName(), is("testQuote"));
210         assertThat(
211                 tests.get(3).getFailureDetail(),
212                 is("junit.framework.AssertionFailedError: \"\n" + "\tat junit.framework.Assert.fail(Assert.java:47)\n"
213                         + "\tat wellFormedXmlFailures.TestSurefire3.testQuote(TestSurefire3.java:25)\n"));
214         assertThat(tests.get(3).getClassName(), is("TestSurefire3"));
215         assertThat(tests.get(3).getTime(), is(0f));
216         assertThat(tests.get(3).getFailureErrorLine(), is("25"));
217         assertThat(tests.get(3).getFailureMessage(), is("\""));
218         assertThat(tests.get(3).getFullName(), is("wellFormedXmlFailures.TestSurefire3.testQuote"));
219         assertThat(tests.get(3).getFailureType(), is("junit.framework.AssertionFailedError"));
220         assertThat(tests.get(3).hasError(), is(false));
221     }
222 
223     @Test
224     public void testParser() throws Exception {
225         TestSuiteXmlParser parser = new TestSuiteXmlParser(consoleLogger);
226 
227         Collection<ReportTestSuite> oldResult = parser.parse(
228                 "src/test/resources/fixture/testsuitexmlparser/TEST-org.apache.maven.surefire.test.FailingTest.xml");
229 
230         assertNotNull(oldResult);
231 
232         assertEquals(1, oldResult.size());
233         ReportTestSuite next = oldResult.iterator().next();
234         assertEquals(2, next.getNumberOfTests());
235     }
236 
237     @Test
238     public void successfulSurefireTestReport() throws Exception {
239         TestSuiteXmlParser parser = new TestSuiteXmlParser(consoleLogger);
240         File surefireReport = new File("src/test/resources/junit-pathWithÜmlaut/TEST-umlautTest.BasicTest.xml");
241         assumeTrue(surefireReport.isFile());
242         Collection<ReportTestSuite> suites = parser.parse(surefireReport.getCanonicalPath());
243         assertNotNull(suites);
244         assertEquals(1, suites.size());
245         ReportTestSuite suite = suites.iterator().next();
246         assertThat(suite.getNumberOfTests(), is(1));
247         assertEquals(1, suite.getNumberOfTests());
248         assertEquals(0, suite.getNumberOfFlakes());
249         assertEquals(0, suite.getNumberOfFailures());
250         assertEquals(0, suite.getNumberOfErrors());
251         assertEquals(0, suite.getNumberOfSkipped());
252         assertThat(suite.getTimeElapsed(), is(0.002f));
253         assertThat(suite.getFullClassName(), is("umlautTest.BasicTest"));
254         assertThat(suite.getPackageName(), is("umlautTest"));
255         assertThat(suite.getName(), is("BasicTest"));
256         ReportTestCase test = suite.getTestCases().iterator().next();
257         assertTrue(test.isSuccessful());
258         assertNull(test.getFailureDetail());
259         assertNull(test.getFailureErrorLine());
260         assertNull(test.getFailureType());
261         assertThat(test.getTime(), is(0.002f));
262         assertThat(test.getFullClassName(), is("umlautTest.BasicTest"));
263         assertThat(test.getClassName(), is("BasicTest"));
264         assertThat(test.getName(), is("testSetUp"));
265         assertThat(test.getFullName(), is("umlautTest.BasicTest.testSetUp"));
266     }
267 
268     @Test
269     public void testParserHitsFailsafeSummary() throws Exception {
270         TestSuiteXmlParser parser = new TestSuiteXmlParser(consoleLogger);
271 
272         parser.parse("src/test/resources/fixture/testsuitexmlparser/failsafe-summary.xml");
273 
274         assertFalse(parser.isValid());
275 
276         parser.parse(
277                 "src/test/resources/fixture/testsuitexmlparser/TEST-org.apache.maven.surefire.test.FailingTest.xml");
278 
279         assertTrue(parser.isValid());
280     }
281 
282     @Test
283     public void lastIndexOfPatternOfOrdinalTest() {
284         final StringBuilder stackTrace = new StringBuilder("\tat org.apache.Test.util(Test.java:60)\n"
285                 + "\tat org.apache.Test.test(Test.java:30)\n" + "\tat com.sun.Impl.xyz(Impl.java:258)\n");
286 
287         int[] result = TestSuiteXmlParser.lastIndexOf(stackTrace, LINE_PATTERNS);
288         assertThat(result[0], is(40));
289         assertThat(result[1], is(0));
290         String errorLine = TestSuiteXmlParser.parseErrorLine(stackTrace, "org.apache.Test");
291         assertThat(errorLine, is("30"));
292     }
293 
294     @Test
295     public void lastIndexOfPatternOfOrdinalTestWithCause() {
296         final StringBuilder stackTrace = new StringBuilder(
297                 "\tat org.apache.Test.util(Test.java:60)\n" + "\tat org.apache.Test.test(Test.java:30)\n"
298                         + "\tat com.sun.Impl.xyz(Impl.java:258)\n"
299                         + "\tat Caused by: java.lang.IndexOutOfBoundsException\n"
300                         + "\tat org.apache.Test.util(Test.java:70)\n");
301 
302         int[] result = TestSuiteXmlParser.lastIndexOf(stackTrace, LINE_PATTERNS);
303         assertThat(result[0], is(40));
304         assertThat(result[1], is(0));
305         String errorLine = TestSuiteXmlParser.parseErrorLine(stackTrace, "org.apache.Test");
306         assertThat(errorLine, is("30"));
307     }
308 
309     @Test
310     public void lastIndexOfPatternOfEnclosedTest() {
311         final StringBuilder source = new StringBuilder("\tat org.apache.Test.util(Test.java:60)\n"
312                 + "\tat org.apache.Test$Nested.test(Test.java:30)\n"
313                 + "\tat com.sun.Impl.xyz(Impl.java:258)\n");
314 
315         int[] result = TestSuiteXmlParser.lastIndexOf(source, LINE_PATTERNS);
316         assertThat(result[0], is(40));
317         assertThat(result[1], is(1));
318         String errorLine = TestSuiteXmlParser.parseErrorLine(source, "org.apache.Test$Nested");
319         assertThat(errorLine, is("30"));
320     }
321 
322     @Test
323     public void lastIndexOfPatternOfEnclosedTestWithCause() {
324         final StringBuilder source = new StringBuilder(
325                 "\tat org.apache.Test.util(Test.java:60)\n" + "\tat org.apache.Test$Nested.test(Test.java:30)\n"
326                         + "\tat com.sun.Impl.xyz(Impl.java:258)\n"
327                         + "\tat Caused by: java.lang.IndexOutOfBoundsException\n"
328                         + "\tat org.apache.Test$Nested.util(Test.java:70)\n");
329 
330         int[] result = TestSuiteXmlParser.lastIndexOf(source, LINE_PATTERNS);
331         assertThat(result[0], is(40));
332         assertThat(result[1], is(1));
333         String errorLine = TestSuiteXmlParser.parseErrorLine(source, "org.apache.Test$Nested");
334         assertThat(errorLine, is("30"));
335     }
336 
337     @Test
338     public void shouldParserEverythingInOrdinalTest() throws Exception {
339         TestSuiteXmlParser parser = new TestSuiteXmlParser(consoleLogger);
340         List<ReportTestSuite> tests =
341                 parser.parse("src/test/resources/fixture/testsuitexmlparser/TEST-surefire.MyTest.xml");
342         assertTrue(parser.isValid());
343         assertThat(tests.size(), is(1));
344         assertThat(tests.get(0).getFullClassName(), is("surefire.MyTest"));
345         assertThat(tests.get(0).getNumberOfErrors(), is(1));
346         assertThat(tests.get(0).getNumberOfFlakes(), is(0));
347         assertThat(tests.get(0).getNumberOfSkipped(), is(0));
348         assertThat(tests.get(0).getNumberOfFailures(), is(0));
349         assertThat(tests.get(0).getPackageName(), is("surefire"));
350         assertThat(tests.get(0).getNumberOfTests(), is(1));
351         assertThat(tests.get(0).getTestCases().size(), is(1));
352         assertFalse(tests.get(0).getTestCases().get(0).isSuccessful());
353         assertThat(tests.get(0).getTestCases().get(0).getFailureErrorLine(), is("13"));
354         assertThat(tests.get(0).getTestCases().get(0).getFailureType(), is("java.lang.RuntimeException"));
355         assertThat(tests.get(0).getTestCases().get(0).getFullClassName(), is("surefire.MyTest"));
356         assertThat(tests.get(0).getTestCases().get(0).getClassName(), is("MyTest"));
357         assertThat(tests.get(0).getTestCases().get(0).getName(), is("test"));
358         assertThat(tests.get(0).getTestCases().get(0).getFullName(), is("surefire.MyTest.test"));
359         assertThat(tests.get(0).getTestCases().get(0).getTime(), is(0.1f));
360         assertThat(tests.get(0).getTestCases().get(0).getFailureMessage(), is("this is different message"));
361 
362         assertThat(
363                 tests.get(0).getTestCases().get(0).getFailureDetail(),
364                 is("java.lang.RuntimeException: java.lang.IndexOutOfBoundsException\n"
365                         + "\tat surefire.MyTest.rethrownDelegate(MyTest.java:24)\n"
366                         + "\tat surefire.MyTest.newRethrownDelegate(MyTest.java:17)\n"
367                         + "\tat surefire.MyTest.test(MyTest.java:13)\n"
368                         + "\tat sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)\n"
369                         + "\tat sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)\n"
370                         + "\tat sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)\n"
371                         + "\tat java.lang.reflect.Method.invoke(Method.java:606)\n"
372                         + "\tat org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)\n"
373                         + "\tat org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)\n"
374                         + "\tat org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)\n"
375                         + "\tat org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)\n"
376                         + "\tat org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)\n"
377                         + "\tat org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)\n"
378                         + "\tat org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)\n"
379                         + "\tat org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)\n"
380                         + "\tat org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)\n"
381                         + "\tat org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)\n"
382                         + "\tat org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)\n"
383                         + "\tat org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)\n"
384                         + "\tat org.junit.runners.ParentRunner.run(ParentRunner.java:363)\n"
385                         + "\tat org.apache.maven.surefire.junit4.JUnit4Provider.execute(JUnit4Provider.java:272)\n"
386                         + "\tat org.apache.maven.surefire.junit4.JUnit4Provider.executeWithRerun(JUnit4Provider.java:167)\n"
387                         + "\tat org.apache.maven.surefire.junit4.JUnit4Provider.executeTestSet(JUnit4Provider.java:147)\n"
388                         + "\tat org.apache.maven.surefire.junit4.JUnit4Provider.invoke(JUnit4Provider.java:130)\n"
389                         + "\tat org.apache.maven.surefire.booter.ForkedBooter.invokeProviderInSameClassLoader(ForkedBooter.java:211)\n"
390                         + "\tat org.apache.maven.surefire.booter.ForkedBooter.runSuitesInProcess(ForkedBooter.java:163)\n"
391                         + "\tat org.apache.maven.surefire.booter.ForkedBooter.main(ForkedBooter.java:105)\n"
392                         + "\tCaused by: java.lang.IndexOutOfBoundsException\n"
393                         + "\tat surefire.MyTest.failure(MyTest.java:33)\n"
394                         + "\tat surefire.MyTest.access$100(MyTest.java:9)\n"
395                         + "\tat surefire.MyTest$Nested.run(MyTest.java:38)\n"
396                         + "\tat surefire.MyTest.delegate(MyTest.java:29)\n"
397                         + "\tat surefire.MyTest.rethrownDelegate(MyTest.java:22)"));
398         assertThat(tests.get(0).getTestCases().get(0).hasError(), is(true));
399     }
400 
401     @Test
402     public void shouldParserEverythingInEnclosedTest() throws Exception {
403         TestSuiteXmlParser parser = new TestSuiteXmlParser(consoleLogger);
404         List<ReportTestSuite> tests =
405                 parser.parse("src/test/resources/fixture/testsuitexmlparser/TEST-surefire.MyTest-enclosed.xml");
406         assertTrue(parser.isValid());
407         assertThat(tests.size(), is(1));
408         assertThat(tests.get(0).getFullClassName(), is("surefire.MyTest$A"));
409         assertThat(tests.get(0).getNumberOfErrors(), is(1));
410         assertThat(tests.get(0).getNumberOfFlakes(), is(0));
411         assertThat(tests.get(0).getNumberOfSkipped(), is(0));
412         assertThat(tests.get(0).getNumberOfFailures(), is(0));
413         assertThat(tests.get(0).getPackageName(), is("surefire"));
414         assertThat(tests.get(0).getNumberOfTests(), is(1));
415         assertThat(tests.get(0).getTestCases().size(), is(1));
416         assertFalse(tests.get(0).getTestCases().get(0).isSuccessful());
417         assertThat(tests.get(0).getTestCases().get(0).getFailureErrorLine(), is("45"));
418         assertThat(tests.get(0).getTestCases().get(0).getFailureType(), is("java.lang.RuntimeException"));
419         assertThat(tests.get(0).getTestCases().get(0).getFullClassName(), is("surefire.MyTest$A"));
420         assertThat(tests.get(0).getTestCases().get(0).getClassName(), is("MyTest$A"));
421         assertThat(tests.get(0).getTestCases().get(0).getName(), is("t"));
422         assertThat(tests.get(0).getTestCases().get(0).getFullName(), is("surefire.MyTest$A.t"));
423         assertThat(tests.get(0).getTestCases().get(0).getTime(), is(0f));
424 
425         assertThat(tests.get(0).getTestCases().get(0).getFailureMessage(), is("java.lang.IndexOutOfBoundsException"));
426 
427         assertThat(
428                 tests.get(0).getTestCases().get(0).getFailureDetail(),
429                 is("java.lang.RuntimeException: java.lang.IndexOutOfBoundsException\n"
430                         + "\tat surefire.MyTest.rethrownDelegate(MyTest.java:24)\n"
431                         + "\tat surefire.MyTest.newRethrownDelegate(MyTest.java:17)\n"
432                         + "\tat surefire.MyTest.access$200(MyTest.java:9)\n"
433                         + "\tat surefire.MyTest$A.t(MyTest.java:45)\n"
434                         + "\tat sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)\n"
435                         + "\tat sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)\n"
436                         + "\tat sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)\n"
437                         + "\tat java.lang.reflect.Method.invoke(Method.java:606)\n"
438                         + "\tat org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)\n"
439                         + "\tat org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)\n"
440                         + "\tat org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)\n"
441                         + "\tat org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)\n"
442                         + "\tat org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)\n"
443                         + "\tat org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)\n"
444                         + "\tat org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)\n"
445                         + "\tat org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)\n"
446                         + "\tat org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)\n"
447                         + "\tat org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)\n"
448                         + "\tat org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)\n"
449                         + "\tat org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)\n"
450                         + "\tat org.junit.runners.ParentRunner.run(ParentRunner.java:363)\n"
451                         + "\tat org.junit.runners.Suite.runChild(Suite.java:128)\n"
452                         + "\tat org.junit.runners.Suite.runChild(Suite.java:27)\n"
453                         + "\tat org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)\n"
454                         + "\tat org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)\n"
455                         + "\tat org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)\n"
456                         + "\tat org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)\n"
457                         + "\tat org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)\n"
458                         + "\tat org.junit.runners.ParentRunner.run(ParentRunner.java:363)\n"
459                         + "\tat org.apache.maven.surefire.junit4.JUnit4Provider.execute(JUnit4Provider.java:272)\n"
460                         + "\tat org.apache.maven.surefire.junit4.JUnit4Provider.executeWithRerun(JUnit4Provider.java:167)\n"
461                         + "\tat org.apache.maven.surefire.junit4.JUnit4Provider.executeTestSet(JUnit4Provider.java:147)\n"
462                         + "\tat org.apache.maven.surefire.junit4.JUnit4Provider.invoke(JUnit4Provider.java:130)\n"
463                         + "\tat org.apache.maven.surefire.booter.ForkedBooter.invokeProviderInSameClassLoader(ForkedBooter.java:211)\n"
464                         + "\tat org.apache.maven.surefire.booter.ForkedBooter.runSuitesInProcess(ForkedBooter.java:163)\n"
465                         + "\tat org.apache.maven.surefire.booter.ForkedBooter.main(ForkedBooter.java:105)\n"
466                         + "\tCaused by: java.lang.IndexOutOfBoundsException\n"
467                         + "\tat surefire.MyTest.failure(MyTest.java:33)\n"
468                         + "\tat surefire.MyTest.access$100(MyTest.java:9)\n"
469                         + "\tat surefire.MyTest$Nested.run(MyTest.java:38)\n"
470                         + "\tat surefire.MyTest.delegate(MyTest.java:29)\n"
471                         + "\tat surefire.MyTest.rethrownDelegate(MyTest.java:22)\n"));
472         assertThat(tests.get(0).getTestCases().get(0).hasError(), is(true));
473     }
474 
475     @Test
476     public void shouldParserEverythingInEnclosedTrimStackTraceTest() throws Exception {
477         TestSuiteXmlParser parser = new TestSuiteXmlParser(consoleLogger);
478         List<ReportTestSuite> tests = parser.parse(
479                 "src/test/resources/fixture/testsuitexmlparser/TEST-surefire.MyTest-enclosed-trimStackTrace.xml");
480         assertTrue(parser.isValid());
481         assertThat(tests.size(), is(1));
482         assertThat(tests.get(0).getFullClassName(), is("surefire.MyTest$A"));
483         assertThat(tests.get(0).getNumberOfErrors(), is(1));
484         assertThat(tests.get(0).getNumberOfFlakes(), is(0));
485         assertThat(tests.get(0).getNumberOfSkipped(), is(0));
486         assertThat(tests.get(0).getNumberOfFailures(), is(0));
487         assertThat(tests.get(0).getPackageName(), is("surefire"));
488         assertThat(tests.get(0).getNumberOfTests(), is(1));
489         assertThat(tests.get(0).getTestCases().size(), is(1));
490         assertFalse(tests.get(0).getTestCases().get(0).isSuccessful());
491         assertThat(tests.get(0).getTestCases().get(0).getFailureErrorLine(), is("45"));
492         assertThat(tests.get(0).getTestCases().get(0).getFailureType(), is("java.lang.RuntimeException"));
493         assertThat(tests.get(0).getTestCases().get(0).getFullClassName(), is("surefire.MyTest$A"));
494         assertThat(tests.get(0).getTestCases().get(0).getClassName(), is("MyTest$A"));
495         assertThat(tests.get(0).getTestCases().get(0).getName(), is("t"));
496         assertThat(tests.get(0).getTestCases().get(0).getFullName(), is("surefire.MyTest$A.t"));
497         assertThat(tests.get(0).getTestCases().get(0).getTime(), is(0f));
498 
499         assertThat(tests.get(0).getTestCases().get(0).getFailureMessage(), is("java.lang.IndexOutOfBoundsException"));
500 
501         assertThat(
502                 tests.get(0).getTestCases().get(0).getFailureDetail(),
503                 is("java.lang.RuntimeException: java.lang.IndexOutOfBoundsException\n"
504                         + "\tat surefire.MyTest.failure(MyTest.java:33)\n"
505                         + "\tat surefire.MyTest.access$100(MyTest.java:9)\n"
506                         + "\tat surefire.MyTest$Nested.run(MyTest.java:38)\n"
507                         + "\tat surefire.MyTest.delegate(MyTest.java:29)\n"
508                         + "\tat surefire.MyTest.rethrownDelegate(MyTest.java:22)\n"
509                         + "\tat surefire.MyTest.newRethrownDelegate(MyTest.java:17)\n"
510                         + "\tat surefire.MyTest.access$200(MyTest.java:9)\n"
511                         + "\tat surefire.MyTest$A.t(MyTest.java:45)\n"));
512         assertThat(tests.get(0).getTestCases().get(0).hasError(), is(true));
513     }
514 
515     @Test
516     public void shouldParserEverythingInNestedClassTest() throws Exception {
517         TestSuiteXmlParser parser = new TestSuiteXmlParser(consoleLogger);
518         List<ReportTestSuite> tests =
519                 parser.parse("src/test/resources/fixture/testsuitexmlparser/TEST-surefire.MyTest-nestedClass.xml");
520         assertTrue(parser.isValid());
521         assertThat(tests.size(), is(1));
522         assertThat(tests.get(0).getFullClassName(), is("surefire.MyTest"));
523         assertThat(tests.get(0).getNumberOfErrors(), is(1));
524         assertThat(tests.get(0).getNumberOfFlakes(), is(0));
525         assertThat(tests.get(0).getNumberOfSkipped(), is(0));
526         assertThat(tests.get(0).getNumberOfFailures(), is(0));
527         assertThat(tests.get(0).getPackageName(), is("surefire"));
528         assertThat(tests.get(0).getNumberOfTests(), is(1));
529         assertThat(tests.get(0).getTestCases().size(), is(1));
530         assertFalse(tests.get(0).getTestCases().get(0).isSuccessful());
531         assertThat(tests.get(0).getTestCases().get(0).getFailureErrorLine(), is("13"));
532         assertThat(tests.get(0).getTestCases().get(0).getFailureType(), is("java.lang.RuntimeException"));
533         assertThat(tests.get(0).getTestCases().get(0).getFullClassName(), is("surefire.MyTest"));
534         assertThat(tests.get(0).getTestCases().get(0).getClassName(), is("MyTest"));
535         assertThat(tests.get(0).getTestCases().get(0).getName(), is("test"));
536         assertThat(tests.get(0).getTestCases().get(0).getFullName(), is("surefire.MyTest.test"));
537         assertThat(tests.get(0).getTestCases().get(0).getTime(), is(0f));
538 
539         assertThat(tests.get(0).getTestCases().get(0).getFailureMessage(), is("java.lang.IndexOutOfBoundsException"));
540 
541         assertThat(
542                 tests.get(0).getTestCases().get(0).getFailureDetail(),
543                 is("java.lang.RuntimeException: java.lang.IndexOutOfBoundsException\n"
544                         + "\tat surefire.MyTest.rethrownDelegate(MyTest.java:24)\n"
545                         + "\tat surefire.MyTest.newRethrownDelegate(MyTest.java:17)\n"
546                         + "\tat surefire.MyTest.test(MyTest.java:13)\n"
547                         + "\tat sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)\n"
548                         + "\tat sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)\n"
549                         + "\tat sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)\n"
550                         + "\tat java.lang.reflect.Method.invoke(Method.java:606)\n"
551                         + "\tat org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)\n"
552                         + "\tat org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)\n"
553                         + "\tat org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)\n"
554                         + "\tat org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)\n"
555                         + "\tat org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)\n"
556                         + "\tat org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)\n"
557                         + "\tat org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)\n"
558                         + "\tat org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)\n"
559                         + "\tat org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)\n"
560                         + "\tat org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)\n"
561                         + "\tat org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)\n"
562                         + "\tat org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)\n"
563                         + "\tat org.junit.runners.ParentRunner.run(ParentRunner.java:363)\n"
564                         + "\tat org.apache.maven.surefire.junit4.JUnit4Provider.execute(JUnit4Provider.java:272)\n"
565                         + "\tat org.apache.maven.surefire.junit4.JUnit4Provider.executeWithRerun(JUnit4Provider.java:167)\n"
566                         + "\tat org.apache.maven.surefire.junit4.JUnit4Provider.executeTestSet(JUnit4Provider.java:147)\n"
567                         + "\tat org.apache.maven.surefire.junit4.JUnit4Provider.invoke(JUnit4Provider.java:130)\n"
568                         + "\tat org.apache.maven.surefire.booter.ForkedBooter.invokeProviderInSameClassLoader(ForkedBooter.java:211)\n"
569                         + "\tat org.apache.maven.surefire.booter.ForkedBooter.runSuitesInProcess(ForkedBooter.java:163)\n"
570                         + "\tat org.apache.maven.surefire.booter.ForkedBooter.main(ForkedBooter.java:105)\n"
571                         + "\tCaused by: java.lang.IndexOutOfBoundsException\n"
572                         + "\tat surefire.MyTest.failure(MyTest.java:33)\n"
573                         + "\tat surefire.MyTest.access$100(MyTest.java:9)\n"
574                         + "\tat surefire.MyTest$Nested.run(MyTest.java:38)\n"
575                         + "\tat surefire.MyTest.delegate(MyTest.java:29)\n"
576                         + "\tat surefire.MyTest.rethrownDelegate(MyTest.java:22)"));
577         assertThat(tests.get(0).getTestCases().get(0).hasError(), is(true));
578     }
579 
580     @Test
581     public void shouldParserEverythingInNestedClassTrimStackTraceTest() throws Exception {
582         TestSuiteXmlParser parser = new TestSuiteXmlParser(consoleLogger);
583         List<ReportTestSuite> tests = parser.parse(
584                 "src/test/resources/fixture/testsuitexmlparser/TEST-surefire.MyTest-nestedClass-trimStackTrace.xml");
585         assertTrue(parser.isValid());
586         assertThat(tests.size(), is(1));
587         assertThat(tests.get(0).getFullClassName(), is("surefire.MyTest"));
588         assertThat(tests.get(0).getNumberOfErrors(), is(1));
589         assertThat(tests.get(0).getNumberOfFlakes(), is(0));
590         assertThat(tests.get(0).getNumberOfSkipped(), is(0));
591         assertThat(tests.get(0).getNumberOfFailures(), is(0));
592         assertThat(tests.get(0).getPackageName(), is("surefire"));
593         assertThat(tests.get(0).getNumberOfTests(), is(1));
594         assertThat(tests.get(0).getTestCases().size(), is(1));
595         assertFalse(tests.get(0).getTestCases().get(0).isSuccessful());
596         assertThat(tests.get(0).getTestCases().get(0).getFailureErrorLine(), is("13"));
597         assertThat(tests.get(0).getTestCases().get(0).getFailureType(), is("java.lang.RuntimeException"));
598         assertThat(tests.get(0).getTestCases().get(0).getFullClassName(), is("surefire.MyTest"));
599         assertThat(tests.get(0).getTestCases().get(0).getClassName(), is("MyTest"));
600         assertThat(tests.get(0).getTestCases().get(0).getName(), is("test"));
601         assertThat(tests.get(0).getTestCases().get(0).getFullName(), is("surefire.MyTest.test"));
602         assertThat(tests.get(0).getTestCases().get(0).getTime(), is(0f));
603 
604         assertThat(tests.get(0).getTestCases().get(0).getFailureMessage(), is("java.lang.IndexOutOfBoundsException"));
605 
606         assertThat(
607                 tests.get(0).getTestCases().get(0).getFailureDetail(),
608                 is("java.lang.RuntimeException: java.lang.IndexOutOfBoundsException\n"
609                         + "\tat surefire.MyTest.rethrownDelegate(MyTest.java:24)\n"
610                         + "\tat surefire.MyTest.newRethrownDelegate(MyTest.java:17)\n"
611                         + "\tat surefire.MyTest.test(MyTest.java:13)\n"
612                         + "\tCaused by: java.lang.IndexOutOfBoundsException\n"
613                         + "\tat surefire.MyTest.failure(MyTest.java:33)\n"
614                         + "\tat surefire.MyTest.access$100(MyTest.java:9)\n"
615                         + "\tat surefire.MyTest$Nested.run(MyTest.java:38)\n"
616                         + "\tat surefire.MyTest.delegate(MyTest.java:29)\n"
617                         + "\tat surefire.MyTest.rethrownDelegate(MyTest.java:22)"));
618         assertThat(tests.get(0).getTestCases().get(0).hasError(), is(true));
619     }
620 
621     @Test
622     public void shouldTestNotBlank() {
623         assertFalse(TestSuiteXmlParser.isNotBlank(1, 2, ' ', ' ', ' ', '\n'));
624         assertFalse(TestSuiteXmlParser.isNotBlank(1, 2, ' ', '\t', ' ', '\n'));
625         assertFalse(TestSuiteXmlParser.isNotBlank(1, 2, ' ', ' ', '\r', '\n'));
626         assertFalse(TestSuiteXmlParser.isNotBlank(1, 2, ' ', ' ', '\f', '\n'));
627         assertTrue(TestSuiteXmlParser.isNotBlank(1, 2, ' ', 'a', ' ', '\n'));
628         assertTrue(TestSuiteXmlParser.isNotBlank(1, 2, ' ', ' ', 'a', '\n'));
629         assertTrue(TestSuiteXmlParser.isNotBlank(1, 2, ' ', 'a', 'b', '\n'));
630     }
631 
632     @Test
633     public void shouldTestIsNumeric() {
634         assertFalse(TestSuiteXmlParser.isNumeric(new StringBuilder("0?5142"), 1, 3));
635         assertTrue(TestSuiteXmlParser.isNumeric(new StringBuilder("0?51M2"), 2, 4));
636         assertFalse(TestSuiteXmlParser.isNumeric(new StringBuilder("0?51M2"), 2, 5));
637     }
638 
639     @Test
640     public void shouldParseLargeFile() throws Exception {
641         // Create test file
642         Path tempFile = Files.createTempFile("largeReport", ".xml");
643 
644         try (BufferedWriter w = Files.newBufferedWriter(tempFile)) {
645             w.write("<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n"
646                     + "<testsuite failures=\"1\" time=\"2.413\" errors=\"0\" skipped=\"0\" tests=\"2\" name=\"largeFile.TestSurefire3\">\n"
647                     + "  <properties></properties>\n"
648                     + "  <testcase time=\"0.005\" classname=\"largeFile.TestSurefire3\" name=\"testSuccess\" />\n"
649                     + "  <testcase time=\"2.20\" classname=\"largeFile.TestSurefire3\" name=\"testFailure\">\n"
650                     + "    <failure message=\"test failure\" type=\"junit.framework.AssertionFailedError\">junit.framework.AssertionFailedError:  \n"
651                     + "\tat junit.framework.Assert.fail(Assert.java:47)\n"
652                     + "\tat largeFile.TestSurefire3.testFailure(TestSurefire3.java:40)\n"
653                     + "</failure>\n"
654                     + "    <system-err><![CDATA[\n");
655 
656             // Adding CDATA which should be ignored during parsing and not cause memory issues
657             for (int i = 0; i < 100000; i++) {
658                 w.write(
659                         "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.\n");
660                 w.flush();
661             }
662             w.write("]]></system-err>\n" + "  </testcase>\n" + "</testsuite>\n");
663             w.flush();
664         }
665 
666         System.err.println(Files.size(tempFile));
667 
668         // Parse test file
669         TestSuiteXmlParser testSuiteXmlParser = new TestSuiteXmlParser(consoleLogger);
670 
671         try (InputStreamReader is = new InputStreamReader(Files.newInputStream(tempFile), UTF_8)) {
672             List<ReportTestSuite> parse = testSuiteXmlParser.parse(is);
673 
674             assertThat(parse.size(), is(1));
675             ReportTestSuite report = parse.get(0);
676             assertThat(report.getFullClassName(), is("largeFile.TestSurefire3"));
677             assertThat(report.getName(), is("TestSurefire3"));
678             assertThat(report.getPackageName(), is("largeFile"));
679             assertThat(report.getNumberOfTests(), is(2));
680             assertThat(report.getNumberOfSkipped(), is(0));
681             assertThat(report.getNumberOfErrors(), is(0));
682             assertThat(report.getNumberOfFailures(), is(1));
683             assertThat(report.getNumberOfFlakes(), is(0));
684             assertThat(report.getTimeElapsed(), is(2.413f));
685             assertThat(report.getTestCases().size(), is(2));
686 
687             List<ReportTestCase> tests = report.getTestCases();
688             assertThat(tests.get(0).getFullClassName(), is("largeFile.TestSurefire3"));
689             assertThat(tests.get(0).getName(), is("testSuccess"));
690             assertNull(tests.get(0).getFailureDetail());
691             assertThat(tests.get(0).getClassName(), is("TestSurefire3"));
692             assertThat(tests.get(0).getTime(), is(0.005f));
693             assertThat(tests.get(0).getFullName(), is("largeFile.TestSurefire3.testSuccess"));
694             assertThat(tests.get(0).hasError(), is(false));
695 
696             assertThat(tests.get(1).getFullClassName(), is("largeFile.TestSurefire3"));
697             assertThat(tests.get(1).getName(), is("testFailure"));
698             assertThat(
699                     tests.get(1).getFailureDetail(),
700                     is("junit.framework.AssertionFailedError:  \n"
701                             + "\tat junit.framework.Assert.fail(Assert.java:47)\n"
702                             + "\tat largeFile.TestSurefire3.testFailure(TestSurefire3.java:40)\n"));
703             assertThat(tests.get(1).getClassName(), is("TestSurefire3"));
704             assertThat(tests.get(1).getTime(), is(2.20f));
705             assertThat(tests.get(1).getFailureErrorLine(), is("40"));
706             assertThat(tests.get(1).getFailureMessage(), is("test failure"));
707             assertThat(tests.get(1).getFullName(), is("largeFile.TestSurefire3.testFailure"));
708             assertThat(tests.get(1).getFailureType(), is("junit.framework.AssertionFailedError"));
709             assertThat(tests.get(1).hasError(), is(false));
710         }
711 
712         // Delete test file
713         Files.delete(tempFile);
714     }
715 
716     @Test
717     public void shouldParseFlakes() throws Exception {
718         // Parse test file
719         TestSuiteXmlParser parser = new TestSuiteXmlParser(consoleLogger);
720 
721         List<ReportTestSuite> testSuites =
722                 parser.parse("src/test/resources/fixture/testsuitexmlparser/TEST-org.acme.FlakyTest.xml");
723         assertTrue(parser.isValid());
724         assertThat(testSuites.size(), is(1));
725 
726         assertThat(testSuites.size(), is(1));
727         ReportTestSuite report = testSuites.get(0);
728         assertThat(report.getFullClassName(), is("org.acme.FlakyTest"));
729         assertThat(report.getName(), is("FlakyTest"));
730         assertThat(report.getPackageName(), is("org.acme"));
731         assertThat(report.getNumberOfTests(), is(2));
732         assertThat(report.getNumberOfSkipped(), is(0));
733         assertThat(report.getNumberOfErrors(), is(0));
734         assertThat(report.getNumberOfFailures(), is(0));
735         assertThat(report.getNumberOfFlakes(), is(4));
736         assertThat(report.getTimeElapsed(), is(1.324f));
737         assertThat(report.getTestCases().size(), is(2));
738 
739         List<ReportTestCase> tests = report.getTestCases();
740         assertThat(tests.get(0).getFullClassName(), is("org.acme.FlakyTest"));
741         assertThat(tests.get(0).getName(), is("testFlaky"));
742         assertNull(tests.get(0).getFailureDetail());
743         assertThat(tests.get(0).getClassName(), is("FlakyTest"));
744         assertThat(tests.get(0).getTime(), is(0.034f));
745         assertThat(tests.get(0).getFullName(), is("org.acme.FlakyTest.testFlaky"));
746         assertThat(tests.get(0).hasError(), is(false));
747         assertThat(tests.get(0).hasFlakes(), is(true));
748 
749         List<FlakyFailure> flakyFailures = tests.get(0).getFlakyFailures();
750         assertThat(flakyFailures.size(), is(3));
751 
752         assertThat(flakyFailures.get(0).getMessage(), startsWith("expected: <1> but was: <0>"));
753         assertThat(flakyFailures.get(0).getType(), is("org.opentest4j.AssertionFailedError"));
754         assertThat(
755                 flakyFailures.get(0).getStackTrace(),
756                 containsString("at org.acme.FlakyTest.testFlaky(FlakyTest.java:18)"));
757 
758         assertThat(flakyFailures.get(1).getMessage(), startsWith("expected: <1> but was: <3>"));
759         assertThat(flakyFailures.get(1).getType(), is("org.opentest4j.AssertionFailedError"));
760         assertThat(
761                 flakyFailures.get(1).getStackTrace(),
762                 containsString("at org.acme.FlakyTest.testFlaky(FlakyTest.java:18)"));
763 
764         assertThat(flakyFailures.get(2).getMessage(), startsWith("expected: <1> but was: <4>"));
765         assertThat(flakyFailures.get(2).getType(), is("org.opentest4j.AssertionFailedError"));
766         assertThat(
767                 flakyFailures.get(2).getStackTrace(),
768                 containsString("at org.acme.FlakyTest.testFlaky(FlakyTest.java:18)"));
769 
770         List<FlakyError> flakyErrors = tests.get(0).getFlakyErrors();
771         assertThat(flakyErrors.size(), is(1));
772         assertThat(flakyErrors.get(0).getMessage(), startsWith("expected: <1> but was: <0>"));
773         assertThat(flakyErrors.get(0).getType(), is("org.opentest4j.AssertionFailedError"));
774         assertThat(
775                 flakyErrors.get(0).getStackTrace(),
776                 containsString("at org.acme.FlakyTest.testFlaky(FlakyTest.java:18)"));
777 
778         assertThat(tests.get(1).getFullClassName(), is("org.acme.FlakyTest"));
779         assertThat(tests.get(1).getName(), is("testStable"));
780         assertThat(tests.get(1).getClassName(), is("FlakyTest"));
781         assertThat(tests.get(1).getTime(), is(0.001f));
782         assertThat(tests.get(1).getFullName(), is("org.acme.FlakyTest.testStable"));
783         assertThat(tests.get(1).hasError(), is(false));
784         assertThat(tests.get(1).hasFlakes(), is(false));
785     }
786 }