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.surefire.junitplatform;
20  
21  import java.lang.reflect.Method;
22  import java.util.Map;
23  import java.util.Optional;
24  
25  import org.apache.maven.surefire.api.report.ReportEntry;
26  import org.apache.maven.surefire.api.report.SimpleReportEntry;
27  import org.apache.maven.surefire.api.report.StackTraceWriter;
28  import org.apache.maven.surefire.api.report.TestOutputReportEntry;
29  import org.apache.maven.surefire.api.report.TestReportListener;
30  import org.apache.maven.surefire.api.report.TestSetReportEntry;
31  import org.apache.maven.surefire.report.PojoStackTraceWriter;
32  import org.junit.Before;
33  import org.junit.Test;
34  import org.junit.jupiter.api.DisplayName;
35  import org.junit.jupiter.api.DisplayNameGenerator;
36  import org.junit.jupiter.engine.config.DefaultJupiterConfiguration;
37  import org.junit.jupiter.engine.config.JupiterConfiguration;
38  import org.junit.jupiter.engine.descriptor.ClassTestDescriptor;
39  import org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor;
40  import org.junit.jupiter.engine.descriptor.TestTemplateTestDescriptor;
41  import org.junit.platform.engine.ConfigurationParameters;
42  import org.junit.platform.engine.TestDescriptor;
43  import org.junit.platform.engine.TestSource;
44  import org.junit.platform.engine.UniqueId;
45  import org.junit.platform.engine.support.descriptor.AbstractTestDescriptor;
46  import org.junit.platform.engine.support.descriptor.ClassSource;
47  import org.junit.platform.engine.support.descriptor.EngineDescriptor;
48  import org.junit.platform.engine.support.descriptor.MethodSource;
49  import org.junit.platform.launcher.TestIdentifier;
50  import org.junit.platform.launcher.TestPlan;
51  import org.mockito.ArgumentCaptor;
52  import org.mockito.InOrder;
53  import org.opentest4j.TestSkippedException;
54  
55  import static java.util.Collections.emptyList;
56  import static java.util.Collections.singleton;
57  import static java.util.Collections.singletonList;
58  import static org.apache.maven.surefire.api.report.RunMode.NORMAL_RUN;
59  import static org.assertj.core.api.Assertions.assertThat;
60  import static org.junit.jupiter.api.Assertions.assertEquals;
61  import static org.junit.jupiter.api.Assertions.assertNotNull;
62  import static org.junit.jupiter.api.Assertions.assertNull;
63  import static org.junit.platform.engine.TestDescriptor.Type.CONTAINER;
64  import static org.junit.platform.engine.TestDescriptor.Type.TEST;
65  import static org.junit.platform.engine.TestExecutionResult.aborted;
66  import static org.junit.platform.engine.TestExecutionResult.failed;
67  import static org.junit.platform.engine.TestExecutionResult.successful;
68  import static org.mockito.ArgumentMatchers.any;
69  import static org.mockito.Mockito.inOrder;
70  import static org.mockito.Mockito.mock;
71  import static org.mockito.Mockito.never;
72  import static org.mockito.Mockito.verify;
73  import static org.mockito.Mockito.verifyNoMoreInteractions;
74  import static org.mockito.Mockito.verifyZeroInteractions;
75  import static org.mockito.Mockito.when;
76  import static org.powermock.reflect.Whitebox.getInternalState;
77  
78  /**
79   * Unit tests for {@link RunListenerAdapter}.
80   *
81   * @since 2.22.0
82   */
83  @SuppressWarnings("checkstyle:magicnumber")
84  public class RunListenerAdapterTest {
85      private static final ConfigurationParameters CONFIG_PARAMS = mock(ConfigurationParameters.class);
86  
87      private TestReportListener<TestOutputReportEntry> listener;
88  
89      private RunListenerAdapter adapter;
90  
91      @Before
92      public void setUp() {
93          listener = mock(TestReportListener.class);
94          adapter = new RunListenerAdapter(listener);
95          adapter.testPlanExecutionStarted(TestPlan.from(emptyList(), CONFIG_PARAMS));
96          adapter.setRunMode(NORMAL_RUN);
97      }
98  
99      @Test
100     public void notifiedWithCorrectNamesWhenMethodExecutionStarted() throws Exception {
101         ArgumentCaptor<ReportEntry> entryCaptor = ArgumentCaptor.forClass(ReportEntry.class);
102 
103         TestPlan testPlan = TestPlan.from(singletonList(new EngineDescriptor(newId(), "Luke's Plan")), CONFIG_PARAMS);
104         adapter.testPlanExecutionStarted(testPlan);
105 
106         TestIdentifier methodIdentifier =
107                 identifiersAsParentOnTestPlan(testPlan, newClassDescriptor(), newMethodDescriptor());
108 
109         adapter.executionStarted(methodIdentifier);
110         verify(listener).testStarting(entryCaptor.capture());
111 
112         ReportEntry entry = entryCaptor.getValue();
113         assertEquals(MY_TEST_METHOD_NAME, entry.getName());
114         assertEquals(MyTestClass.class.getName(), entry.getSourceName());
115         assertNull(entry.getStackTraceWriter());
116     }
117 
118     @Test
119     public void notifiedWithCompatibleNameForMethodWithArguments() throws Exception {
120         ArgumentCaptor<ReportEntry> entryCaptor = ArgumentCaptor.forClass(ReportEntry.class);
121 
122         TestPlan testPlan = TestPlan.from(singletonList(new EngineDescriptor(newId(), "Luke's Plan")), CONFIG_PARAMS);
123         adapter.testPlanExecutionStarted(testPlan);
124 
125         TestIdentifier methodIdentifier =
126                 identifiersAsParentOnTestPlan(testPlan, newClassDescriptor(), newMethodDescriptor(String.class));
127 
128         adapter.executionStarted(methodIdentifier);
129         verify(listener).testStarting(entryCaptor.capture());
130 
131         ReportEntry entry = entryCaptor.getValue();
132         assertEquals(MY_TEST_METHOD_NAME + "(String)", entry.getName());
133         assertNull(entry.getNameText());
134         assertEquals(MyTestClass.class.getName(), entry.getSourceName());
135         assertNull(entry.getSourceText());
136         assertNull(entry.getStackTraceWriter());
137     }
138 
139     @Test
140     public void notifiedEagerlyForTestSetWhenClassExecutionStarted() throws Exception {
141         EngineDescriptor engine = newEngineDescriptor();
142         TestDescriptor parent = newClassDescriptor();
143         engine.addChild(parent);
144         TestDescriptor child = newMethodDescriptor();
145         parent.addChild(child);
146         TestPlan plan = TestPlan.from(singletonList(engine), CONFIG_PARAMS);
147 
148         String className = MyTestClass.class.getName();
149 
150         adapter.testPlanExecutionStarted(plan);
151         adapter.executionStarted(TestIdentifier.from(engine));
152         adapter.executionStarted(TestIdentifier.from(parent));
153         verify(listener)
154                 .testSetStarting(new SimpleReportEntry(NORMAL_RUN, 0x0000000100000000L, className, null, null, null));
155         verifyNoMoreInteractions(listener);
156 
157         adapter.executionStarted(TestIdentifier.from(child));
158         verify(listener)
159                 .testStarting(new SimpleReportEntry(
160                         NORMAL_RUN, 0x0000000100000001L, className, null, MY_TEST_METHOD_NAME, null));
161         verifyNoMoreInteractions(listener);
162 
163         adapter.executionFinished(TestIdentifier.from(child), successful());
164         ArgumentCaptor<SimpleReportEntry> report = ArgumentCaptor.forClass(SimpleReportEntry.class);
165         verify(listener).testSucceeded(report.capture());
166         assertThat(report.getValue().getRunMode()).isEqualTo(NORMAL_RUN);
167         assertThat(report.getValue().getTestRunId()).isEqualTo(0x0000000100000001L);
168         assertThat(report.getValue().getSourceName()).isEqualTo(className);
169         assertThat(report.getValue().getSourceText()).isNull();
170         assertThat(report.getValue().getName()).isEqualTo(MY_TEST_METHOD_NAME);
171         assertThat(report.getValue().getNameText()).isNull();
172         assertThat(report.getValue().getElapsed()).isNotNull();
173         assertThat(report.getValue().getSystemProperties()).isEmpty();
174         verifyNoMoreInteractions(listener);
175 
176         adapter.executionFinished(TestIdentifier.from(parent), successful());
177         report = ArgumentCaptor.forClass(SimpleReportEntry.class);
178         verify(listener).testSetCompleted(report.capture());
179         assertThat(report.getValue().getSourceName()).isEqualTo(className);
180         assertThat(report.getValue().getName()).isNull();
181         assertThat(report.getValue().getElapsed()).isNotNull();
182         assertThat(report.getValue().getSystemProperties()).isNotEmpty();
183         verifyNoMoreInteractions(listener);
184 
185         adapter.executionFinished(TestIdentifier.from(engine), successful());
186         verifyNoMoreInteractions(listener);
187     }
188 
189     @Test
190     public void displayNamesInClassAndMethods() throws Exception {
191         EngineDescriptor engine = newEngineDescriptor();
192         TestDescriptor parent = newClassDescriptor("parent");
193         engine.addChild(parent);
194 
195         UniqueId id1 = parent.getUniqueId().append(MyTestClass.class.getName(), MY_NAMED_TEST_METHOD_NAME);
196         Method m1 = MyTestClass.class.getDeclaredMethod(MY_NAMED_TEST_METHOD_NAME);
197         TestDescriptor child1 = new TestMethodTestDescriptorWithDisplayName(id1, MyTestClass.class, m1, "dn1");
198         parent.addChild(child1);
199 
200         UniqueId id2 = parent.getUniqueId().append(MyTestClass.class.getName(), MY_TEST_METHOD_NAME);
201         Method m2 = MyTestClass.class.getDeclaredMethod(MY_TEST_METHOD_NAME, String.class);
202         TestDescriptor child2 = new TestMethodTestDescriptor(
203                 id2, MyTestClass.class, m2, new DefaultJupiterConfiguration(CONFIG_PARAMS));
204         parent.addChild(child2);
205 
206         TestPlan plan = TestPlan.from(singletonList(engine), CONFIG_PARAMS);
207 
208         InOrder inOrder = inOrder(listener);
209 
210         adapter.testPlanExecutionStarted(plan);
211 
212         adapter.executionStarted(TestIdentifier.from(engine));
213         adapter.executionStarted(TestIdentifier.from(parent));
214         ArgumentCaptor<SimpleReportEntry> report = ArgumentCaptor.forClass(SimpleReportEntry.class);
215         inOrder.verify(listener).testSetStarting(report.capture());
216         assertThat(report.getValue().getTestRunId()).isEqualTo(0x0000000100000000L);
217         assertThat(report.getValue().getSourceName()).isEqualTo(MyTestClass.class.getName());
218         assertThat(report.getValue().getSourceText()).isEqualTo("parent");
219         assertThat(report.getValue().getName()).isNull();
220         assertThat(report.getValue().getSystemProperties()).isEmpty();
221         verifyZeroInteractions(listener);
222 
223         adapter.executionStarted(TestIdentifier.from(child1));
224         inOrder.verify(listener)
225                 .testStarting(new SimpleReportEntry(
226                         NORMAL_RUN,
227                         0x0000000100000001L,
228                         MyTestClass.class.getName(),
229                         "parent",
230                         MY_NAMED_TEST_METHOD_NAME,
231                         "dn1"));
232         inOrder.verifyNoMoreInteractions();
233 
234         adapter.executionFinished(TestIdentifier.from(child1), successful());
235         report = ArgumentCaptor.forClass(SimpleReportEntry.class);
236         inOrder.verify(listener).testSucceeded(report.capture());
237         assertThat(report.getValue().getRunMode()).isEqualTo(NORMAL_RUN);
238         assertThat(report.getValue().getTestRunId()).isEqualTo(0x0000000100000001L);
239         assertThat(report.getValue().getSourceName()).isEqualTo(MyTestClass.class.getName());
240         assertThat(report.getValue().getSourceText()).isEqualTo("parent");
241         assertThat(report.getValue().getName()).isEqualTo(MY_NAMED_TEST_METHOD_NAME);
242         assertThat(report.getValue().getNameText()).isEqualTo("dn1");
243         assertThat(report.getValue().getElapsed()).isNotNull();
244         assertThat(report.getValue().getSystemProperties()).isEmpty();
245         inOrder.verifyNoMoreInteractions();
246 
247         adapter.executionStarted(TestIdentifier.from(child2));
248         inOrder.verify(listener)
249                 .testStarting(new SimpleReportEntry(
250                         NORMAL_RUN,
251                         0x0000000100000002L,
252                         MyTestClass.class.getName(),
253                         "parent",
254                         MY_TEST_METHOD_NAME + "(String)",
255                         null));
256         inOrder.verifyNoMoreInteractions();
257 
258         Exception assumptionFailure = new Exception();
259         adapter.executionFinished(TestIdentifier.from(child2), aborted(assumptionFailure));
260         report = ArgumentCaptor.forClass(SimpleReportEntry.class);
261         inOrder.verify(listener).testAssumptionFailure(report.capture());
262         assertThat(report.getValue().getRunMode()).isEqualTo(NORMAL_RUN);
263         assertThat(report.getValue().getTestRunId()).isEqualTo(0x0000000100000002L);
264         assertThat(report.getValue().getSourceName()).isEqualTo(MyTestClass.class.getName());
265         assertThat(report.getValue().getSourceText()).isEqualTo("parent");
266         assertThat(report.getValue().getName()).isEqualTo(MY_TEST_METHOD_NAME + "(String)");
267         assertThat(report.getValue().getNameText()).isNull();
268         assertThat(report.getValue().getElapsed()).isNotNull();
269         assertThat(report.getValue().getSystemProperties()).isEmpty();
270         assertThat(report.getValue().getStackTraceWriter()).isNotNull();
271         assertThat(report.getValue().getStackTraceWriter().getThrowable().getTarget())
272                 .isSameAs(assumptionFailure);
273         inOrder.verifyNoMoreInteractions();
274 
275         adapter.executionFinished(TestIdentifier.from(parent), successful());
276         inOrder.verify(listener).testSetCompleted(report.capture());
277         assertThat(report.getValue().getSourceName()).isEqualTo(MyTestClass.class.getName());
278         assertThat(report.getValue().getSourceText()).isEqualTo("parent");
279         assertThat(report.getValue().getName()).isNull();
280         assertThat(report.getValue().getNameText()).isNull();
281         assertThat(report.getValue().getElapsed()).isNotNull();
282         assertThat(report.getValue().getSystemProperties()).isNotEmpty();
283         assertThat(report.getValue().getStackTraceWriter()).isNull();
284         inOrder.verifyNoMoreInteractions();
285 
286         adapter.executionFinished(TestIdentifier.from(engine), successful());
287         inOrder.verifyNoMoreInteractions();
288     }
289 
290     @Test
291     public void notifiedForUnclassifiedTestIdentifier() {
292         EngineDescriptor engine = new EngineDescriptor(UniqueId.forEngine("engine"), "engine") {
293             @Override
294             public Type getType() {
295                 return TEST;
296             }
297         };
298         TestPlan plan = TestPlan.from(singletonList(engine), CONFIG_PARAMS);
299 
300         adapter.testPlanExecutionStarted(plan);
301         assertThat((TestPlan) getInternalState(adapter, "testPlan")).isSameAs(plan);
302         assertThat((Map) getInternalState(adapter, "testStartTime")).isEmpty();
303 
304         adapter.executionStarted(TestIdentifier.from(engine));
305         verify(listener)
306                 .testStarting(new SimpleReportEntry(NORMAL_RUN, 0x0000000100000001L, "engine", null, "engine", null));
307         verifyNoMoreInteractions(listener);
308 
309         adapter.executionFinished(TestIdentifier.from(engine), successful());
310         ArgumentCaptor<SimpleReportEntry> report = ArgumentCaptor.forClass(SimpleReportEntry.class);
311         verify(listener).testSucceeded(report.capture());
312         assertThat(report.getValue().getRunMode()).isEqualTo(NORMAL_RUN);
313         assertThat(report.getValue().getTestRunId()).isEqualTo(0x0000000100000001L);
314         assertThat(report.getValue().getSourceName()).isEqualTo("engine");
315         assertThat(report.getValue().getSourceText()).isNull();
316         assertThat(report.getValue().getName()).isEqualTo("engine");
317         assertThat(report.getValue().getNameText()).isNull();
318         assertThat(report.getValue().getElapsed()).isNotNull();
319         assertThat(report.getValue().getStackTraceWriter()).isNull();
320         assertThat(report.getValue().getSystemProperties()).isEmpty();
321 
322         adapter.testPlanExecutionFinished(plan);
323         assertThat((TestPlan) getInternalState(adapter, "testPlan")).isNull();
324         assertThat((Map) getInternalState(adapter, "testStartTime")).isEmpty();
325 
326         verifyNoMoreInteractions(listener);
327     }
328 
329     @Test
330     public void notNotifiedWhenEngineExecutionStarted() {
331         adapter.executionStarted(newEngineIdentifier());
332         verify(listener, never()).testStarting(any());
333     }
334 
335     @Test
336     public void notifiedWhenMethodExecutionSkipped() throws Exception {
337         adapter.executionSkipped(newMethodIdentifier(), "test");
338         verify(listener).testSkipped(any());
339     }
340 
341     @Test
342     public void notifiedWithCorrectNamesWhenClassExecutionSkipped() throws Exception {
343         EngineDescriptor engineDescriptor = new EngineDescriptor(newId(), "Luke's Plan");
344         TestDescriptor classTestDescriptor = newClassDescriptor();
345         TestDescriptor method1 = newMethodDescriptor();
346         classTestDescriptor.addChild(method1);
347         TestDescriptor method2 = newMethodDescriptor();
348         classTestDescriptor.addChild(method2);
349         engineDescriptor.addChild(classTestDescriptor);
350         TestPlan testPlan = TestPlan.from(singletonList(engineDescriptor), CONFIG_PARAMS);
351         adapter.testPlanExecutionStarted(testPlan);
352 
353         TestIdentifier classIdentifier =
354                 identifiersAsParentOnTestPlan(testPlan, newEngineDescriptor(), newClassDescriptor());
355 
356         ArgumentCaptor<TestSetReportEntry> entryCaptor1 = ArgumentCaptor.forClass(TestSetReportEntry.class);
357         ArgumentCaptor<ReportEntry> entryCaptor2 = ArgumentCaptor.forClass(ReportEntry.class);
358         ArgumentCaptor<ReportEntry> entryCaptor3 = ArgumentCaptor.forClass(ReportEntry.class);
359         ArgumentCaptor<TestSetReportEntry> entryCaptor4 = ArgumentCaptor.forClass(TestSetReportEntry.class);
360 
361         adapter.executionSkipped(classIdentifier, "test");
362         verify(listener).testSetStarting(entryCaptor1.capture());
363         verify(listener).testSkipped(entryCaptor2.capture());
364         verify(listener).testSkipped(entryCaptor3.capture());
365         verify(listener).testSetCompleted(entryCaptor4.capture());
366 
367         ReportEntry entry1 = entryCaptor1.getValue();
368         assertNull(entry1.getName());
369         assertEquals(MyTestClass.class.getTypeName(), entry1.getSourceName());
370 
371         ReportEntry entry4 = entryCaptor1.getValue();
372         assertNull(entry4.getName());
373         assertEquals(MyTestClass.class.getTypeName(), entry4.getSourceName());
374     }
375 
376     @Test
377     public void notifiedWhenMethodExecutionAborted() throws Exception {
378         adapter.executionFinished(newMethodIdentifier(), aborted(null));
379         verify(listener).testAssumptionFailure(any());
380     }
381 
382     @Test
383     public void notifiedWhenClassExecutionAborted() {
384         TestSkippedException t = new TestSkippedException("skipped");
385         adapter.executionFinished(newClassIdentifier(), aborted(t));
386         String source = MyTestClass.class.getName();
387         StackTraceWriter stw = new PojoStackTraceWriter(source, null, t);
388         ArgumentCaptor<SimpleReportEntry> report = ArgumentCaptor.forClass(SimpleReportEntry.class);
389         verify(listener).testSetCompleted(report.capture());
390         assertThat(report.getValue().getSourceName()).isEqualTo(source);
391         assertThat(report.getValue().getStackTraceWriter()).isEqualTo(stw);
392     }
393 
394     @Test
395     public void notifiedOfContainerFailureWhenErrored() throws Exception {
396         adapter.executionFinished(newContainerIdentifier(), failed(new RuntimeException()));
397         verify(listener).testError(any());
398     }
399 
400     @Test
401     public void notifiedOfContainerFailureWhenFailed() throws Exception {
402         adapter.executionFinished(newContainerIdentifier(), failed(new AssertionError()));
403         verify(listener).testFailed(any());
404     }
405 
406     @Test
407     public void notifiedWhenMethodExecutionFailed() throws Exception {
408         adapter.executionFinished(newMethodIdentifier(), failed(new AssertionError()));
409         verify(listener).testFailed(any());
410     }
411 
412     @Test
413     public void notifiedWhenMethodExecutionFailedWithError() throws Exception {
414         adapter.executionFinished(newMethodIdentifier(), failed(new RuntimeException()));
415         verify(listener).testError(any());
416     }
417 
418     @Test
419     public void notifiedWithCorrectNamesWhenClassExecutionFailed() {
420         ArgumentCaptor<ReportEntry> entryCaptor = ArgumentCaptor.forClass(ReportEntry.class);
421         TestPlan testPlan = TestPlan.from(singletonList(new EngineDescriptor(newId(), "Luke's Plan")), CONFIG_PARAMS);
422         adapter.testPlanExecutionStarted(testPlan);
423 
424         adapter.executionFinished(
425                 identifiersAsParentOnTestPlan(testPlan, newClassDescriptor()), failed(new AssertionError()));
426         verify(listener).testFailed(entryCaptor.capture());
427 
428         ReportEntry entry = entryCaptor.getValue();
429         assertEquals(MyTestClass.class.getTypeName(), entry.getSourceName());
430         assertNull(entry.getName());
431         assertNotNull(entry.getStackTraceWriter());
432         assertNotNull(entry.getStackTraceWriter().getThrowable());
433         assertThat(entry.getStackTraceWriter().getThrowable().getTarget()).isInstanceOf(AssertionError.class);
434     }
435 
436     @Test
437     public void notifiedWithCorrectNamesWhenClassExecutionErrored() {
438         ArgumentCaptor<ReportEntry> entryCaptor = ArgumentCaptor.forClass(ReportEntry.class);
439         TestPlan testPlan = TestPlan.from(singletonList(new EngineDescriptor(newId(), "Luke's Plan")), CONFIG_PARAMS);
440         adapter.testPlanExecutionStarted(testPlan);
441 
442         adapter.executionFinished(
443                 identifiersAsParentOnTestPlan(testPlan, newClassDescriptor()), failed(new RuntimeException()));
444         verify(listener).testError(entryCaptor.capture());
445 
446         ReportEntry entry = entryCaptor.getValue();
447         assertEquals(MyTestClass.class.getTypeName(), entry.getSourceName());
448         assertNull(entry.getName());
449         assertNotNull(entry.getStackTraceWriter());
450         assertNotNull(entry.getStackTraceWriter().getThrowable());
451         assertThat(entry.getStackTraceWriter().getThrowable().getTarget()).isInstanceOf(RuntimeException.class);
452     }
453 
454     @Test
455     public void notifiedWithCorrectNamesWhenContainerFailed() throws Exception {
456         ArgumentCaptor<ReportEntry> entryCaptor = ArgumentCaptor.forClass(ReportEntry.class);
457         TestPlan testPlan = TestPlan.from(singletonList(new EngineDescriptor(newId(), "Luke's Plan")), CONFIG_PARAMS);
458         adapter.testPlanExecutionStarted(testPlan);
459 
460         adapter.executionFinished(newContainerIdentifier(), failed(new RuntimeException()));
461         verify(listener).testError(entryCaptor.capture());
462 
463         ReportEntry entry = entryCaptor.getValue();
464         assertEquals(MyTestClass.class.getTypeName(), entry.getSourceName());
465         assertEquals(MY_TEST_METHOD_NAME, entry.getName());
466         assertNotNull(entry.getStackTraceWriter());
467         assertNotNull(entry.getStackTraceWriter().getThrowable());
468         assertThat(entry.getStackTraceWriter().getThrowable().getTarget()).isInstanceOf(RuntimeException.class);
469     }
470 
471     @Test
472     public void notifiedWhenMethodExecutionSucceeded() throws Exception {
473         adapter.executionFinished(newMethodIdentifier(), successful());
474         verify(listener).testSucceeded(any());
475     }
476 
477     @Test
478     public void notifiedForTestSetWhenClassExecutionSucceeded() {
479         EngineDescriptor engineDescriptor = newEngineDescriptor();
480         TestDescriptor classDescriptor = newClassDescriptor();
481         engineDescriptor.addChild(classDescriptor);
482         adapter.testPlanExecutionStarted(TestPlan.from(singleton(engineDescriptor), CONFIG_PARAMS));
483         adapter.executionStarted(TestIdentifier.from(classDescriptor));
484 
485         adapter.executionFinished(TestIdentifier.from(classDescriptor), successful());
486 
487         String className = MyTestClass.class.getName();
488 
489         verify(listener)
490                 .testSetStarting(new SimpleReportEntry(NORMAL_RUN, 0x0000000100000000L, className, null, null, null));
491 
492         ArgumentCaptor<SimpleReportEntry> report = ArgumentCaptor.forClass(SimpleReportEntry.class);
493         verify(listener).testSetCompleted(report.capture());
494         assertThat(report.getValue().getRunMode()).isEqualTo(NORMAL_RUN);
495         assertThat(report.getValue().getTestRunId()).isEqualTo(0x0000000100000000L);
496         assertThat(report.getValue().getSourceName()).isEqualTo(className);
497         assertThat(report.getValue().getSourceText()).isNull();
498         assertThat(report.getValue().getName()).isNull();
499         assertThat(report.getValue().getNameText()).isNull();
500         assertThat(report.getValue().getStackTraceWriter()).isNull();
501         assertThat(report.getValue().getElapsed()).isNotNull();
502         assertThat(report.getValue().getSystemProperties()).isNotEmpty();
503 
504         verify(listener, never()).testSucceeded(any());
505 
506         verifyNoMoreInteractions(listener);
507     }
508 
509     @Test
510     public void notifiedWithParentDisplayNameWhenTestClassUnknown() {
511         // Set up a test plan
512         TestPlan plan = TestPlan.from(singletonList(new EngineDescriptor(newId(), "Luke's Plan")), CONFIG_PARAMS);
513         adapter.testPlanExecutionStarted(plan);
514 
515         // Use the test plan to set up child with parent.
516         final String parentDisplay = "I am your father";
517         TestIdentifier child = newSourcelessChildIdentifierWithParent(plan, parentDisplay, null);
518         adapter.executionStarted(child);
519 
520         // Check that the adapter has informed Surefire that the test has been invoked,
521         // with the parent name as source (since the test case itself had no source).
522         ArgumentCaptor<ReportEntry> entryCaptor = ArgumentCaptor.forClass(ReportEntry.class);
523         verify(listener).testStarting(entryCaptor.capture());
524         assertEquals(parentDisplay, entryCaptor.getValue().getSourceName());
525         assertNull(entryCaptor.getValue().getSourceText());
526         assertNull(entryCaptor.getValue().getName());
527         assertNull(entryCaptor.getValue().getNameText());
528     }
529 
530     @Test
531     public void stackTraceWriterPresentWhenParentHasSource() {
532         TestPlan plan = TestPlan.from(singletonList(new EngineDescriptor(newId(), "Some Plan")), CONFIG_PARAMS);
533         adapter.testPlanExecutionStarted(plan);
534 
535         TestIdentifier child =
536                 newSourcelessChildIdentifierWithParent(plan, "Parent", ClassSource.from(MyTestClass.class));
537         adapter.executionFinished(child, failed(new RuntimeException()));
538         ArgumentCaptor<ReportEntry> entryCaptor = ArgumentCaptor.forClass(ReportEntry.class);
539         verify(listener).testError(entryCaptor.capture());
540         assertNotNull(entryCaptor.getValue().getStackTraceWriter());
541     }
542 
543     @Test
544     public void stackTraceWriterDefaultsToTestClass() {
545         TestPlan plan = TestPlan.from(singletonList(new EngineDescriptor(newId(), "Some Plan")), CONFIG_PARAMS);
546         adapter.testPlanExecutionStarted(plan);
547 
548         TestIdentifier child = newSourcelessChildIdentifierWithParent(plan, "Parent", null);
549         adapter.executionFinished(child, failed(new RuntimeException("message")));
550         ArgumentCaptor<ReportEntry> entryCaptor = ArgumentCaptor.forClass(ReportEntry.class);
551         verify(listener).testError(entryCaptor.capture());
552         assertNotNull(entryCaptor.getValue().getStackTraceWriter());
553         assertNotNull(entryCaptor.getValue().getStackTraceWriter().smartTrimmedStackTrace());
554         assertNotNull(entryCaptor.getValue().getStackTraceWriter().writeTraceToString());
555         assertNotNull(entryCaptor.getValue().getStackTraceWriter().writeTrimmedTraceToString());
556     }
557 
558     @Test
559     public void stackTraceWriterPresentEvenWithoutException() throws Exception {
560         adapter.executionFinished(newMethodIdentifier(), failed(null));
561         ArgumentCaptor<ReportEntry> entryCaptor = ArgumentCaptor.forClass(ReportEntry.class);
562         verify(listener).testError(entryCaptor.capture());
563         assertNotNull(entryCaptor.getValue().getStackTraceWriter());
564     }
565 
566     @Test
567     public void displayNamesIgnoredInReport() throws NoSuchMethodException {
568         TestMethodTestDescriptorWithDisplayName descriptor = new TestMethodTestDescriptorWithDisplayName(
569                 newId(),
570                 MyTestClass.class,
571                 MyTestClass.class.getDeclaredMethod("myNamedTestMethod"),
572                 "some display name");
573 
574         TestIdentifier factoryIdentifier = TestIdentifier.from(descriptor);
575         ArgumentCaptor<ReportEntry> entryCaptor = ArgumentCaptor.forClass(ReportEntry.class);
576 
577         adapter.executionSkipped(factoryIdentifier, "");
578         verify(listener).testSkipped(entryCaptor.capture());
579 
580         ReportEntry value = entryCaptor.getValue();
581 
582         assertEquals(MyTestClass.class.getName(), value.getSourceName());
583         assertNull(value.getSourceText());
584         assertEquals("myNamedTestMethod", value.getName());
585         assertEquals("some display name", value.getNameText());
586     }
587 
588     private static TestIdentifier newMethodIdentifier() throws Exception {
589         return TestIdentifier.from(newMethodDescriptor());
590     }
591 
592     private static TestDescriptor newMethodDescriptor(Class<?>... parameterTypes) throws Exception {
593         return new TestMethodTestDescriptor(
594                 UniqueId.forEngine("method"),
595                 MyTestClass.class,
596                 MyTestClass.class.getDeclaredMethod(MY_TEST_METHOD_NAME, parameterTypes),
597                 new DefaultJupiterConfiguration(CONFIG_PARAMS));
598     }
599 
600     private static TestIdentifier newClassIdentifier() {
601         return TestIdentifier.from(newClassDescriptor());
602     }
603 
604     private static TestDescriptor newClassDescriptor(String displayName) {
605         JupiterConfiguration jupiterConfiguration = mock(JupiterConfiguration.class);
606         DisplayNameGenerator displayNameGenerator = mock(DisplayNameGenerator.class);
607         when(displayNameGenerator.generateDisplayNameForClass(MyTestClass.class))
608                 .thenReturn(displayName);
609         when(jupiterConfiguration.getDefaultDisplayNameGenerator()).thenReturn(displayNameGenerator);
610         return new ClassTestDescriptor(
611                 UniqueId.root("class", MyTestClass.class.getName()), MyTestClass.class, jupiterConfiguration) {};
612     }
613 
614     private static TestDescriptor newClassDescriptor() {
615         return new ClassTestDescriptor(
616                 UniqueId.root("class", MyTestClass.class.getName()),
617                 MyTestClass.class,
618                 new DefaultJupiterConfiguration(CONFIG_PARAMS));
619     }
620 
621     private static TestIdentifier newSourcelessChildIdentifierWithParent(
622             TestPlan testPlan, String parentDisplay, TestSource parentTestSource) {
623         // A parent test identifier with a name.
624         TestDescriptor parent = mock(TestDescriptor.class);
625         when(parent.getUniqueId()).thenReturn(newId());
626         when(parent.getDisplayName()).thenReturn(parentDisplay);
627         when(parent.getLegacyReportingName()).thenReturn(parentDisplay);
628         when(parent.getSource()).thenReturn(Optional.ofNullable(parentTestSource));
629         when(parent.getType()).thenReturn(CONTAINER);
630         TestIdentifier parentId = TestIdentifier.from(parent);
631 
632         // The (child) test case that is to be executed as part of a test plan.
633         TestDescriptor child = mock(TestDescriptor.class);
634         when(child.getUniqueId()).thenReturn(newId());
635         when(child.getType()).thenReturn(TEST);
636         when(child.getLegacyReportingName()).thenReturn("child");
637 
638         // Ensure the child source is null yet that there is a parent -- the special case to be tested.
639         when(child.getSource()).thenReturn(Optional.empty());
640         when(child.getParent()).thenReturn(Optional.of(parent));
641         TestIdentifier childId = TestIdentifier.from(child);
642 
643         testPlan.addInternal(childId);
644         testPlan.addInternal(parentId);
645 
646         return childId;
647     }
648 
649     private static TestIdentifier newContainerIdentifier() throws Exception {
650         return TestIdentifier.from(new TestTemplateTestDescriptor(
651                 UniqueId.forEngine("method"),
652                 MyTestClass.class,
653                 MyTestClass.class.getDeclaredMethod(MY_TEST_METHOD_NAME),
654                 new DefaultJupiterConfiguration(CONFIG_PARAMS)));
655     }
656 
657     private static TestIdentifier newEngineIdentifier() {
658         TestDescriptor testDescriptor = newEngineDescriptor();
659         return TestIdentifier.from(testDescriptor);
660     }
661 
662     private static EngineDescriptor newEngineDescriptor() {
663         return new EngineDescriptor(UniqueId.forEngine("engine"), "engine");
664     }
665 
666     private static TestIdentifier identifiersAsParentOnTestPlan(
667             TestPlan plan, TestDescriptor parent, TestDescriptor child) {
668         child.setParent(parent);
669 
670         TestIdentifier parentIdentifier = TestIdentifier.from(parent);
671         TestIdentifier childIdentifier = TestIdentifier.from(child);
672 
673         plan.addInternal(parentIdentifier);
674         plan.addInternal(childIdentifier);
675 
676         return childIdentifier;
677     }
678 
679     private static TestIdentifier identifiersAsParentOnTestPlan(TestPlan plan, TestDescriptor root) {
680         TestIdentifier rootIdentifier = TestIdentifier.from(root);
681         plan.addInternal(rootIdentifier);
682         return rootIdentifier;
683     }
684 
685     private static UniqueId newId() {
686         return UniqueId.forEngine("engine");
687     }
688 
689     private static final String MY_TEST_METHOD_NAME = "myTestMethod";
690     private static final String MY_NAMED_TEST_METHOD_NAME = "myNamedTestMethod";
691 
692     private static class MyTestClass {
693         @org.junit.jupiter.api.Test
694         void myTestMethod() {}
695 
696         @org.junit.jupiter.api.Test
697         void myTestMethod(String foo) {}
698 
699         @DisplayName("name")
700         @org.junit.jupiter.api.Test
701         void myNamedTestMethod() {}
702     }
703 
704     static class TestMethodTestDescriptorWithDisplayName extends AbstractTestDescriptor {
705         private TestMethodTestDescriptorWithDisplayName(
706                 UniqueId uniqueId, Class<?> testClass, Method testMethod, String displayName) {
707             super(uniqueId, displayName, MethodSource.from(testClass, testMethod));
708         }
709 
710         @Override
711         public Type getType() {
712             return Type.TEST;
713         }
714     }
715 }