Skip to content

Commit aebce57

Browse files
committed
Report discovery issues for invalid tag syntax on class level
1 parent cb7582e commit aebce57

File tree

4 files changed

+51
-18
lines changed

4 files changed

+51
-18
lines changed

junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/descriptor/ClassBasedTestDescriptor.java

+19-4
Original file line numberDiff line numberDiff line change
@@ -136,18 +136,26 @@ public final String getLegacyReportingName() {
136136
public final void validate(DiscoveryIssueReporter reporter) {
137137
validateCoreLifecycleMethods(reporter);
138138
validateClassTemplateInvocationLifecycleMethods(reporter);
139+
validateTags(reporter);
139140
}
140141

141142
protected void validateCoreLifecycleMethods(DiscoveryIssueReporter reporter) {
142-
List<DiscoveryIssue> discoveryIssues = this.lifecycleMethods.discoveryIssues;
143-
discoveryIssues.forEach(reporter::reportIssue);
144-
discoveryIssues.clear();
143+
reportAndClear(this.lifecycleMethods.discoveryIssues, reporter);
145144
}
146145

147146
protected void validateClassTemplateInvocationLifecycleMethods(DiscoveryIssueReporter reporter) {
148147
LifecycleMethodUtils.validateNoClassTemplateInvocationLifecycleMethodsAreDeclared(getTestClass(), reporter);
149148
}
150149

150+
private void validateTags(DiscoveryIssueReporter reporter) {
151+
reportAndClear(this.classInfo.discoveryIssues, reporter);
152+
}
153+
154+
private static void reportAndClear(List<DiscoveryIssue> discoveryIssues, DiscoveryIssueReporter reporter) {
155+
discoveryIssues.forEach(reporter::reportIssue);
156+
discoveryIssues.clear();
157+
}
158+
151159
// --- Node ----------------------------------------------------------------
152160

153161
@Override
@@ -539,6 +547,8 @@ private void invokeMethodInExtensionContext(Method method, ExtensionContext cont
539547

540548
protected static class ClassInfo {
541549

550+
private final List<DiscoveryIssue> discoveryIssues = new ArrayList<>();
551+
542552
final Class<?> testClass;
543553
final Set<TestTag> tags;
544554
final Lifecycle lifecycle;
@@ -547,7 +557,12 @@ protected static class ClassInfo {
547557

548558
ClassInfo(Class<?> testClass, JupiterConfiguration configuration) {
549559
this.testClass = testClass;
550-
this.tags = getTags(testClass);
560+
List<DiscoveryIssue.Builder> tagIssues = new ArrayList<>();
561+
this.tags = getTags(testClass, tagIssues::add);
562+
if (!tagIssues.isEmpty()) {
563+
ClassSource source = ClassSource.from(testClass);
564+
tagIssues.forEach(builder -> discoveryIssues.add(builder.source(source).build()));
565+
}
551566
this.lifecycle = getTestInstanceLifecycle(testClass, configuration);
552567
this.defaultChildExecutionMode = (this.lifecycle == Lifecycle.PER_CLASS ? ExecutionMode.SAME_THREAD : null);
553568
this.exclusiveResourceCollector = ExclusiveResourceCollector.from(testClass);

junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/descriptor/JupiterTestDescriptor.java

+6-13
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
import java.util.List;
2626
import java.util.Optional;
2727
import java.util.Set;
28+
import java.util.function.Consumer;
2829
import java.util.function.Supplier;
2930
import java.util.function.UnaryOperator;
3031

@@ -39,10 +40,10 @@
3940
import org.junit.jupiter.engine.execution.JupiterEngineExecutionContext;
4041
import org.junit.jupiter.engine.extension.ExtensionRegistry;
4142
import org.junit.platform.commons.JUnitException;
42-
import org.junit.platform.commons.logging.Logger;
43-
import org.junit.platform.commons.logging.LoggerFactory;
4443
import org.junit.platform.commons.util.ExceptionUtils;
4544
import org.junit.platform.commons.util.UnrecoverableExceptions;
45+
import org.junit.platform.engine.DiscoveryIssue;
46+
import org.junit.platform.engine.DiscoveryIssue.Severity;
4647
import org.junit.platform.engine.TestDescriptor;
4748
import org.junit.platform.engine.TestSource;
4849
import org.junit.platform.engine.TestTag;
@@ -58,8 +59,6 @@
5859
public abstract class JupiterTestDescriptor extends AbstractTestDescriptor
5960
implements Node<JupiterEngineExecutionContext> {
6061

61-
private static final Logger logger = LoggerFactory.getLogger(JupiterTestDescriptor.class);
62-
6362
private static final ConditionEvaluator conditionEvaluator = new ConditionEvaluator();
6463

6564
final JupiterConfiguration configuration;
@@ -77,21 +76,15 @@ public abstract class JupiterTestDescriptor extends AbstractTestDescriptor
7776

7877
// --- TestDescriptor ------------------------------------------------------
7978

80-
static Set<TestTag> getTags(AnnotatedElement element) {
79+
static Set<TestTag> getTags(AnnotatedElement element, Consumer<DiscoveryIssue.Builder> invalidTagHandler) {
8180
// @formatter:off
8281
return findRepeatableAnnotations(element, Tag.class).stream()
8382
.map(Tag::value)
8483
.filter(tag -> {
8584
boolean isValid = TestTag.isValid(tag);
8685
if (!isValid) {
87-
// TODO [#242] Replace logging with precondition check once we have a proper mechanism for
88-
// handling validation exceptions during the TestEngine discovery phase.
89-
//
90-
// As an alternative to a precondition check here, we could catch any
91-
// PreconditionViolationException thrown by TestTag::create.
92-
logger.warn(() -> String.format(
93-
"Configuration error: invalid tag syntax in @Tag(\"%s\") declaration on [%s]. Tag will be ignored.",
94-
tag, element));
86+
String message = String.format("Invalid tag syntax in @Tag(\"%s\") declaration on [%s]. Tag will be ignored.", tag, element);
87+
invalidTagHandler.accept(DiscoveryIssue.builder(Severity.WARNING, message));
9588
}
9689
return isValid;
9790
})

junit-jupiter-engine/src/main/java/org/junit/jupiter/engine/descriptor/MethodBasedTestDescriptor.java

+2-1
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,8 @@ public abstract class MethodBasedTestDescriptor extends JupiterTestDescriptor
7575

7676
this.testClass = Preconditions.notNull(testClass, "Class must not be null");
7777
this.testMethod = testMethod;
78-
this.tags = getTags(testMethod);
78+
this.tags = getTags(testMethod,
79+
builder -> logger.warn(() -> "Configuration error: " + builder.build().message()));
7980
}
8081

8182
@Override

jupiter-tests/src/test/java/org/junit/jupiter/engine/discovery/DiscoveryTests.java

+24
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535

3636
import org.junit.jupiter.api.Named;
3737
import org.junit.jupiter.api.Nested;
38+
import org.junit.jupiter.api.Tag;
3839
import org.junit.jupiter.api.Test;
3940
import org.junit.jupiter.api.TestInfo;
4041
import org.junit.jupiter.api.TestTemplate;
@@ -48,6 +49,7 @@
4849
import org.junit.jupiter.params.provider.MethodSource;
4950
import org.junit.platform.engine.DiscoveryIssue;
5051
import org.junit.platform.engine.TestDescriptor;
52+
import org.junit.platform.engine.support.descriptor.ClassSource;
5153
import org.junit.platform.launcher.LauncherDiscoveryRequest;
5254

5355
/**
@@ -284,6 +286,20 @@ void reportsWarningForTestClassWithPotentialNestedTestClasses() {
284286
InvalidTestCases.InvalidTestClassTestCase.class.getName());
285287
}
286288

289+
@Test
290+
void reportsWarningsForInvalidTags() {
291+
292+
var results = discoverTestsForClass(InvalidTagsTestCase.class);
293+
294+
var discoveryIssues = results.getDiscoveryIssues();
295+
assertThat(discoveryIssues).hasSize(1);
296+
assertThat(discoveryIssues.getFirst().message()) //
297+
.isEqualTo("Invalid tag syntax in @Tag(\"\") declaration on [class %s]. Tag will be ignored.",
298+
InvalidTagsTestCase.class.getName());
299+
assertThat(discoveryIssues.getFirst().source()) //
300+
.contains(ClassSource.from(InvalidTagsTestCase.class));
301+
}
302+
287303
// -------------------------------------------------------------------
288304

289305
@SuppressWarnings("unused")
@@ -393,4 +409,12 @@ private class InvalidTestClassSubclassTestCase extends InvalidTestClassTestCase
393409

394410
}
395411

412+
@SuppressWarnings("JUnitMalformedDeclaration")
413+
@Tag("")
414+
static class InvalidTagsTestCase {
415+
@Test
416+
void test() {
417+
}
418+
}
419+
396420
}

0 commit comments

Comments
 (0)