|
33 | 33 | import java.util.Optional;
|
34 | 34 | import java.util.concurrent.ConcurrentHashMap;
|
35 | 35 | import java.util.concurrent.ConcurrentMap;
|
| 36 | +import java.util.regex.Matcher; |
| 37 | +import java.util.regex.Pattern; |
36 | 38 | import java.util.stream.Stream;
|
37 | 39 |
|
38 | 40 | import org.apache.maven.surefire.api.report.OutputReportEntry;
|
|
60 | 62 | final class RunListenerAdapter
|
61 | 63 | implements TestExecutionListener, TestOutputReceiver<OutputReportEntry>, RunModeSetter
|
62 | 64 | {
|
| 65 | + private static final Pattern COMMA_PATTERN = Pattern.compile( "," ); |
| 66 | + |
63 | 67 | private final ClassMethodIndexer classMethodIndexer = new ClassMethodIndexer();
|
64 | 68 | private final ConcurrentMap<TestIdentifier, Long> testStartTime = new ConcurrentHashMap<>();
|
65 | 69 | private final ConcurrentMap<TestIdentifier, TestExecutionResult> failures = new ConcurrentHashMap<>();
|
@@ -362,6 +366,23 @@ private String[] toClassMethodName( TestIdentifier testIdentifier )
|
362 | 366 | // param || m()[1] | [1] <param>
|
363 | 367 | // param+displ || m()[1] | displ
|
364 | 368 |
|
| 369 | + // Override resulting methodDesc/methodDisp values again, for invocations of |
| 370 | + // JUnit5 templated-tests (such as @ParameterizedTest/@RepeatedTest) |
| 371 | + Integer templatedTestInvocationId = extractTemplatedInvocationId( testIdentifier ); |
| 372 | + if ( templatedTestInvocationId != null ) |
| 373 | + { |
| 374 | + String simpleClassNames = COMMA_PATTERN.splitAsStream( methodSource.getMethodParameterTypes() ) |
| 375 | + .map( s -> s.substring( 1 + s.lastIndexOf( '.' ) ).trim() ) |
| 376 | + .collect( joining( ", " ) ); |
| 377 | + |
| 378 | + String methodSignature = methodName + '(' + simpleClassNames + ')'; |
| 379 | + |
| 380 | + String invocationIdStr = "[" + templatedTestInvocationId + "]"; |
| 381 | + |
| 382 | + methodDesc = methodSignature + invocationIdStr; |
| 383 | + methodDisp = parentDisplay + display; |
| 384 | + } |
| 385 | + |
365 | 386 | return new String[] {source[0], source[1], methodDesc, methodDisp};
|
366 | 387 | }
|
367 | 388 | else if ( testSource.filter( ClassSource.class::isInstance ).isPresent() )
|
@@ -390,6 +411,39 @@ else if ( testSource.filter( ClassSource.class::isInstance ).isPresent() )
|
390 | 411 | }
|
391 | 412 | }
|
392 | 413 |
|
| 414 | + private static final Pattern TEST_TEMPLATE_INVOCATION_MATCHER = |
| 415 | + Pattern.compile( "\\[test-template-invocation:#([1-9][0-9]*)]" ); |
| 416 | + |
| 417 | + /** |
| 418 | + * If the given test-id defines an invocation of a templated-test (such as a specific |
| 419 | + * instance of a @ParameterizedTest or @RepeatedTest), returns the invocation-id of |
| 420 | + * that instance (1, 2, ...) |
| 421 | + * |
| 422 | + * <p>Returns null if the given test-id doesn't seem to be a templated-test invocation, |
| 423 | + * or if no invocation-id could be extracted. |
| 424 | + */ |
| 425 | + private Integer extractTemplatedInvocationId( TestIdentifier testId ) |
| 426 | + { |
| 427 | + /* |
| 428 | + Note: with JUnit 5.8+, we could make this nicer using testId.getUniqueIdObject() |
| 429 | +
|
| 430 | + # Segment lastSegment = testId.getUniqueIdObject().getLastSegment(); |
| 431 | + # if (lastSegment.getType().equals(TestTemplateInvocationTestDescriptor.SEGMENT_TYPE)) { |
| 432 | + # String invocationIdStr = lastSegment.getValue(); // #1, #2, ... |
| 433 | + # if (invocationIdStr.startsWith("#")) { // assuming always true |
| 434 | + # return Integer.valueOf(invocationIdStr.substring(1)); |
| 435 | + # } |
| 436 | + # } |
| 437 | + */ |
| 438 | + Matcher m = TEST_TEMPLATE_INVOCATION_MATCHER.matcher( testId.getUniqueId() ); |
| 439 | + if ( m.find() ) |
| 440 | + { |
| 441 | + String group = m.group( 1 ); |
| 442 | + return Integer.valueOf( group ); |
| 443 | + } |
| 444 | + return null; |
| 445 | + } |
| 446 | + |
393 | 447 | /**
|
394 | 448 | * @return Map of tests that failed.
|
395 | 449 | */
|
|
0 commit comments