Skip to content

Commit 7b95bd2

Browse files
authored
Clarify test descriptor implementation requirements (#5170)
* Define test and container as non-exclusive properties. * Use emphasis to distinguish between term and word. * Document that `TestDescriptor.Type` values are exclusive properties. * Document that `isContainer()` and `isTest()` must be consistent with `getType()`. * Document that `getChildren()`, `getDescendants()` and `mayRegisterTests()` must be consistent with `isContainer()`. * Document that only the hierarchy of the test descriptor is mutable after discovery.
1 parent 153a1e5 commit 7b95bd2

File tree

3 files changed

+48
-8
lines changed

3 files changed

+48
-8
lines changed

documentation/src/docs/asciidoc/release-notes/release-notes-6.1.0-M2.adoc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ repository on GitHub.
1616
[[release-notes-6.1.0-M2-junit-platform-bug-fixes]]
1717
==== Bug Fixes
1818

19-
*
19+
* Clarify `TestDescriptor` implementation requirements.
2020

2121
[[release-notes-6.1.0-M2-junit-platform-deprecations-and-breaking-changes]]
2222
==== Deprecations and Breaking Changes

documentation/src/docs/asciidoc/user-guide/advanced-topics/engines.adoc

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,8 @@ to the following requirements:
9595
* The `TestDescriptor` returned from `TestEngine.discover()` _must_ be the root of a tree
9696
of `TestDescriptor` instances. This implies that there _must not_ be any cycles between
9797
a node and its descendants.
98+
* The hierarchy of test descriptors returned from `TestEngine.discover()` _must_ be
99+
mutable, but the test descriptors _must_ otherwise be immutable after discovery.
98100
* A `TestEngine` _must_ be able to discover `UniqueIdSelectors` for any unique ID that it
99101
previously generated and returned from `TestEngine.discover()`. This enables selecting a
100102
subset of tests to execute or rerun.

junit-platform-engine/src/main/java/org/junit/platform/engine/TestDescriptor.java

Lines changed: 45 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,8 @@
2727
import org.junit.platform.commons.util.Preconditions;
2828

2929
/**
30-
* Mutable descriptor for a test or container that has been discovered by a
31-
* {@link TestEngine}.
30+
* A descriptor with a mutable hierarchy for a test or container that has been
31+
* discovered by a {@link TestEngine}.
3232
*
3333
* @since 1.0
3434
* @see TestEngine
@@ -42,6 +42,9 @@ public interface TestDescriptor {
4242
* <p>Uniqueness must be guaranteed across an entire test plan,
4343
* regardless of how many engines are used behind the scenes.
4444
*
45+
* <p>The implementation must treat this property as immutable after test
46+
* discovery has completed.
47+
*
4548
* @return the {@code UniqueId} for this descriptor; never {@code null}
4649
*/
4750
UniqueId getUniqueId();
@@ -77,6 +80,9 @@ default String getLegacyReportingName() {
7780
/**
7881
* Get the set of {@linkplain TestTag tags} associated with this descriptor.
7982
*
83+
* <p>The implementation must treat this property as immutable after test
84+
* discovery has completed.
85+
*
8086
* @return the set of tags associated with this descriptor; never {@code null}
8187
* but potentially empty
8288
* @see TestTag
@@ -87,6 +93,9 @@ default String getLegacyReportingName() {
8793
* Get the {@linkplain TestSource source} of the test or container described
8894
* by this descriptor, if available.
8995
*
96+
* <p>The implementation must treat this property as immutable after test
97+
* discovery has completed.
98+
*
9099
* @see TestSource
91100
*/
92101
Optional<TestSource> getSource();
@@ -106,6 +115,9 @@ default String getLegacyReportingName() {
106115
/**
107116
* Get the immutable set of <em>children</em> of this descriptor.
108117
*
118+
* <p>The implementation must be consistent with {@link #isContainer()} such that
119+
* {@code !x.container()} implies {@code x.getChildren().isEmpty()}.
120+
*
109121
* @return the set of children of this descriptor; neither {@code null}
110122
* nor mutable, but potentially empty
111123
* @see #getDescendants()
@@ -141,6 +153,9 @@ default Set<? extends TestDescriptor> getAncestors() {
141153
* <p>A <em>descendant</em> is a child of this descriptor or a child of one of
142154
* its children, recursively.
143155
*
156+
* <p>The implementation must be consistent with {@link #isContainer()} such that
157+
* {@code !x.container()} implies {@code x.getDescendants().isEmpty()}.
158+
*
144159
* @see #getChildren()
145160
*/
146161
default Set<? extends TestDescriptor> getDescendants() {
@@ -223,14 +238,24 @@ default boolean isRoot() {
223238
/**
224239
* Determine the {@link Type} of this descriptor.
225240
*
241+
* <p>The implementation must treat this property as immutable after test
242+
* discovery has completed.
243+
*
226244
* @return the descriptor type; never {@code null}.
227245
* @see #isContainer()
228246
* @see #isTest()
229247
*/
230248
Type getType();
231249

232250
/**
233-
* Determine if this descriptor describes a container.
251+
* Determine if this descriptor describes a <em>container</em>.
252+
*
253+
* <p>A test descriptor is a <em>container</em> when it may contain other
254+
* containers or tests as its children. In addition to being a
255+
* <em>container</em> this test descriptor may also be a <em>test</em>.
256+
*
257+
* <p>The implementation must be consistent with {@link #getType()} such
258+
* that {@code x.isContainer()} equals {@code x.getType().isContainer()}.
234259
*
235260
* <p>The default implementation delegates to {@link Type#isContainer()}.
236261
*/
@@ -239,7 +264,14 @@ default boolean isContainer() {
239264
}
240265

241266
/**
242-
* Determine if this descriptor describes a test.
267+
* Determine if this descriptor describes a <em>test</em>.
268+
*
269+
* <p>A test descriptor is a <em>test</em> when it verifies expected
270+
* behavior when executed. In addition to being a <em>test</em> this
271+
* test descriptor may also be a <em>container</em>.
272+
*
273+
* <p>The implementation must be consistent with {@link #getType()} such
274+
* that {@code x.isTest()} equals {@code x.getType().isTest()}.
243275
*
244276
* <p>The default implementation delegates to {@link Type#isTest()}.
245277
*/
@@ -250,6 +282,10 @@ default boolean isTest() {
250282
/**
251283
* Determine if this descriptor may register dynamic tests during execution.
252284
*
285+
* <p>The implementation must treat this property as immutable after test
286+
* discovery has completed and must be consistent with {@link #isContainer()}
287+
* such that {@code !x.container()} implies {@code !x.mayRegisterTests()}.
288+
*
253289
* <p>The default implementation assumes tests are usually known during
254290
* discovery and thus returns {@code false}.
255291
*/
@@ -259,7 +295,7 @@ default boolean mayRegisterTests() {
259295

260296
/**
261297
* Determine if the supplied descriptor (or any of its descendants)
262-
* {@linkplain TestDescriptor#isTest() is a test} or
298+
* {@linkplain TestDescriptor#isTest() is a <em>test</em>} or
263299
* {@linkplain TestDescriptor#mayRegisterTests() may potentially register
264300
* tests dynamically}.
265301
*
@@ -355,12 +391,14 @@ static Visitor composite(Visitor... visitors) {
355391
enum Type {
356392

357393
/**
358-
* Denotes that the {@link TestDescriptor} is for a <em>container</em>.
394+
* Denotes that the {@link TestDescriptor} is strictly for a
395+
* <em>container</em>. I.e. it is not also a <em>test</em>.
359396
*/
360397
CONTAINER,
361398

362399
/**
363-
* Denotes that the {@link TestDescriptor} is for a <em>test</em>.
400+
* Denotes that the {@link TestDescriptor} is strictly for a
401+
* <em>test</em>. I.e. it is not also a <em>container</em>.
364402
*/
365403
TEST,
366404

0 commit comments

Comments
 (0)