1111package org .junit .jupiter .engine .discovery ;
1212
1313import static org .junit .platform .commons .support .AnnotationSupport .findAnnotation ;
14+ import static org .junit .platform .commons .support .AnnotationSupport .isAnnotated ;
1415
1516import java .util .List ;
1617import java .util .Optional ;
1718import java .util .function .Consumer ;
1819
1920import org .junit .jupiter .api .MethodOrderer ;
21+ import org .junit .jupiter .api .Order ;
2022import org .junit .jupiter .api .TestMethodOrder ;
2123import org .junit .jupiter .engine .config .JupiterConfiguration ;
2224import org .junit .jupiter .engine .descriptor .ClassBasedTestDescriptor ;
2325import org .junit .jupiter .engine .descriptor .JupiterTestDescriptor ;
2426import org .junit .jupiter .engine .descriptor .MethodBasedTestDescriptor ;
2527import org .junit .platform .commons .support .ReflectionSupport ;
28+ import org .junit .platform .engine .DiscoveryIssue ;
29+ import org .junit .platform .engine .DiscoveryIssue .Severity ;
2630import org .junit .platform .engine .TestDescriptor ;
31+ import org .junit .platform .engine .support .descriptor .MethodSource ;
32+ import org .junit .platform .engine .support .discovery .DiscoveryIssueReporter ;
33+ import org .junit .platform .engine .support .discovery .DiscoveryIssueReporter .Condition ;
2734
2835/**
2936 * @since 5.5
3037 */
3138class MethodOrderingVisitor extends AbstractOrderingVisitor {
3239
3340 private final JupiterConfiguration configuration ;
41+ private final Condition <MethodBasedTestDescriptor > noOrderAnnotation ;
3442
35- MethodOrderingVisitor (JupiterConfiguration configuration ) {
43+ MethodOrderingVisitor (JupiterConfiguration configuration , DiscoveryIssueReporter issueReporter ) {
3644 this .configuration = configuration ;
45+ this .noOrderAnnotation = issueReporter .createReportingCondition (
46+ testDescriptor -> !isAnnotated (testDescriptor .getTestMethod (), Order .class ), testDescriptor -> {
47+ String message = String .format (
48+ "Ineffective @Order annotation on method '%s'. It will not be applied because MethodOrderer.OrderAnnotation is not in use." ,
49+ testDescriptor .getTestMethod ().toGenericString ());
50+ return DiscoveryIssue .builder (Severity .INFO , message ) //
51+ .source (MethodSource .from (testDescriptor .getTestMethod ())) //
52+ .build ();
53+ });
3754 }
3855
3956 @ Override
@@ -54,37 +71,62 @@ protected boolean shouldNonMatchingDescriptorsComeBeforeOrderedOnes() {
5471 * @since 5.4
5572 */
5673 private void orderContainedMethods (ClassBasedTestDescriptor classBasedTestDescriptor , Class <?> testClass ) {
57- findAnnotation (testClass , TestMethodOrder .class )//
74+ Optional < MethodOrderer > methodOrderer = findAnnotation (testClass , TestMethodOrder .class )//
5875 .map (TestMethodOrder ::value )//
5976 .<MethodOrderer > map (ReflectionSupport ::newInstance )//
6077 .map (Optional ::of )//
61- .orElseGet (configuration ::getDefaultTestMethodOrderer )//
62- .ifPresent (methodOrderer -> {
63-
64- Consumer <List <DefaultMethodDescriptor >> orderingAction = methodDescriptors -> methodOrderer .orderMethods (
65- new DefaultMethodOrdererContext (testClass , methodDescriptors , this .configuration ));
66-
67- MessageGenerator descriptorsAddedMessageGenerator = number -> String .format (
68- "MethodOrderer [%s] added %s MethodDescriptor(s) for test class [%s] which will be ignored." ,
69- methodOrderer .getClass ().getName (), number , testClass .getName ());
70- MessageGenerator descriptorsRemovedMessageGenerator = number -> String .format (
71- "MethodOrderer [%s] removed %s MethodDescriptor(s) for test class [%s] which will be retained with arbitrary ordering." ,
72- methodOrderer .getClass ().getName (), number , testClass .getName ());
73-
74- DescriptorWrapperOrderer <DefaultMethodDescriptor > descriptorWrapperOrderer = new DescriptorWrapperOrderer <>(
75- orderingAction , descriptorsAddedMessageGenerator , descriptorsRemovedMessageGenerator );
76-
77- orderChildrenTestDescriptors (classBasedTestDescriptor , //
78- MethodBasedTestDescriptor .class , //
79- DefaultMethodDescriptor ::new , //
80- descriptorWrapperOrderer );
81-
82- // Note: MethodOrderer#getDefaultExecutionMode() is guaranteed
83- // to be invoked after MethodOrderer#orderMethods().
84- methodOrderer .getDefaultExecutionMode ()//
85- .map (JupiterTestDescriptor ::toExecutionMode )//
86- .ifPresent (classBasedTestDescriptor ::setDefaultChildExecutionMode );
87- });
78+ .orElseGet (configuration ::getDefaultTestMethodOrderer );
79+ orderContainedMethods (classBasedTestDescriptor , testClass , methodOrderer );
80+ }
81+
82+ private void orderContainedMethods (ClassBasedTestDescriptor classBasedTestDescriptor , Class <?> testClass ,
83+ Optional <MethodOrderer > methodOrderer ) {
84+ DescriptorWrapperOrderer <?, DefaultMethodDescriptor > descriptorWrapperOrderer = createDescriptorWrapperOrderer (
85+ testClass , methodOrderer );
86+
87+ orderChildrenTestDescriptors (classBasedTestDescriptor , //
88+ MethodBasedTestDescriptor .class , //
89+ toValidationAction (methodOrderer ), //
90+ DefaultMethodDescriptor ::new , //
91+ descriptorWrapperOrderer );
92+
93+ // Note: MethodOrderer#getDefaultExecutionMode() is guaranteed
94+ // to be invoked after MethodOrderer#orderMethods().
95+ methodOrderer //
96+ .flatMap (it -> it .getDefaultExecutionMode ().map (JupiterTestDescriptor ::toExecutionMode )) //
97+ .ifPresent (classBasedTestDescriptor ::setDefaultChildExecutionMode );
98+ }
99+
100+ private DescriptorWrapperOrderer <?, DefaultMethodDescriptor > createDescriptorWrapperOrderer (Class <?> testClass ,
101+ Optional <MethodOrderer > methodOrderer ) {
102+
103+ return methodOrderer //
104+ .map (it -> createDescriptorWrapperOrderer (testClass , it )) //
105+ .orElseGet (DescriptorWrapperOrderer ::noop );
106+
107+ }
108+
109+ private DescriptorWrapperOrderer <?, DefaultMethodDescriptor > createDescriptorWrapperOrderer (Class <?> testClass ,
110+ MethodOrderer methodOrderer ) {
111+ Consumer <List <DefaultMethodDescriptor >> orderingAction = methodDescriptors -> methodOrderer .orderMethods (
112+ new DefaultMethodOrdererContext (testClass , methodDescriptors , this .configuration ));
113+
114+ MessageGenerator descriptorsAddedMessageGenerator = number -> String .format (
115+ "MethodOrderer [%s] added %s MethodDescriptor(s) for test class [%s] which will be ignored." ,
116+ methodOrderer .getClass ().getName (), number , testClass .getName ());
117+ MessageGenerator descriptorsRemovedMessageGenerator = number -> String .format (
118+ "MethodOrderer [%s] removed %s MethodDescriptor(s) for test class [%s] which will be retained with arbitrary ordering." ,
119+ methodOrderer .getClass ().getName (), number , testClass .getName ());
120+
121+ return new DescriptorWrapperOrderer <>(methodOrderer , orderingAction , descriptorsAddedMessageGenerator ,
122+ descriptorsRemovedMessageGenerator );
123+ }
124+
125+ private Optional <Consumer <MethodBasedTestDescriptor >> toValidationAction (Optional <MethodOrderer > methodOrderer ) {
126+ if (methodOrderer .orElse (null ) instanceof MethodOrderer .OrderAnnotation ) {
127+ return Optional .empty ();
128+ }
129+ return Optional .of (noOrderAnnotation ::check );
88130 }
89131
90132}
0 commit comments