diff --git a/documentation/src/docs/asciidoc/release-notes/release-notes-6.1.0-M2.adoc b/documentation/src/docs/asciidoc/release-notes/release-notes-6.1.0-M2.adoc index 4f40bc523b81..4def1151ca40 100644 --- a/documentation/src/docs/asciidoc/release-notes/release-notes-6.1.0-M2.adoc +++ b/documentation/src/docs/asciidoc/release-notes/release-notes-6.1.0-M2.adoc @@ -16,7 +16,7 @@ repository on GitHub. [[release-notes-6.1.0-M2-junit-platform-bug-fixes]] ==== Bug Fixes -* ❓ +* Clarify `TestDescriptor` implementation requirements. [[release-notes-6.1.0-M2-junit-platform-deprecations-and-breaking-changes]] ==== Deprecations and Breaking Changes diff --git a/documentation/src/docs/asciidoc/user-guide/advanced-topics/engines.adoc b/documentation/src/docs/asciidoc/user-guide/advanced-topics/engines.adoc index 03615613456f..8876443f0461 100644 --- a/documentation/src/docs/asciidoc/user-guide/advanced-topics/engines.adoc +++ b/documentation/src/docs/asciidoc/user-guide/advanced-topics/engines.adoc @@ -95,6 +95,8 @@ to the following requirements: * The `TestDescriptor` returned from `TestEngine.discover()` _must_ be the root of a tree of `TestDescriptor` instances. This implies that there _must not_ be any cycles between a node and its descendants. +* The hierarchy of test descriptors returned from `TestEngine.discover()` _must_ be + mutable, but the test descriptors _must_ otherwise be immutable after discovery. * A `TestEngine` _must_ be able to discover `UniqueIdSelectors` for any unique ID that it previously generated and returned from `TestEngine.discover()`. This enables selecting a subset of tests to execute or rerun. diff --git a/junit-platform-engine/src/main/java/org/junit/platform/engine/TestDescriptor.java b/junit-platform-engine/src/main/java/org/junit/platform/engine/TestDescriptor.java index 8d146c05b616..0dc47bca49cc 100644 --- a/junit-platform-engine/src/main/java/org/junit/platform/engine/TestDescriptor.java +++ b/junit-platform-engine/src/main/java/org/junit/platform/engine/TestDescriptor.java @@ -27,8 +27,8 @@ import org.junit.platform.commons.util.Preconditions; /** - * Mutable descriptor for a test or container that has been discovered by a - * {@link TestEngine}. + * A descriptor with a mutable hierarchy for a test or container that has been + * discovered by a {@link TestEngine}. * * @since 1.0 * @see TestEngine @@ -42,6 +42,9 @@ public interface TestDescriptor { *
Uniqueness must be guaranteed across an entire test plan, * regardless of how many engines are used behind the scenes. * + *
The implementation must treat this property as immutable after test + * discovery has completed. + * * @return the {@code UniqueId} for this descriptor; never {@code null} */ UniqueId getUniqueId(); @@ -77,6 +80,9 @@ default String getLegacyReportingName() { /** * Get the set of {@linkplain TestTag tags} associated with this descriptor. * + *
The implementation must treat this property as immutable after test + * discovery has completed. + * * @return the set of tags associated with this descriptor; never {@code null} * but potentially empty * @see TestTag @@ -87,6 +93,9 @@ default String getLegacyReportingName() { * Get the {@linkplain TestSource source} of the test or container described * by this descriptor, if available. * + *
The implementation must treat this property as immutable after test
+ * discovery has completed.
+ *
* @see TestSource
*/
Optional The implementation must be consistent with {@link #isContainer()} such that
+ * {@code !x.container()} implies {@code x.getChildren().isEmpty()}.
+ *
* @return the set of children of this descriptor; neither {@code null}
* nor mutable, but potentially empty
* @see #getDescendants()
@@ -141,6 +153,9 @@ default Set extends TestDescriptor> getAncestors() {
* A descendant is a child of this descriptor or a child of one of
* its children, recursively.
*
+ * The implementation must be consistent with {@link #isContainer()} such that
+ * {@code !x.container()} implies {@code x.getDescendants().isEmpty()}.
+ *
* @see #getChildren()
*/
default Set extends TestDescriptor> getDescendants() {
@@ -223,6 +238,9 @@ default boolean isRoot() {
/**
* Determine the {@link Type} of this descriptor.
*
+ * The implementation must treat this property as immutable after test
+ * discovery has completed.
+ *
* @return the descriptor type; never {@code null}.
* @see #isContainer()
* @see #isTest()
@@ -230,7 +248,14 @@ default boolean isRoot() {
Type getType();
/**
- * Determine if this descriptor describes a container.
+ * Determine if this descriptor describes a container.
+ *
+ * A test descriptor is a container when it may contain other
+ * containers or tests as its children. In addition to being a
+ * container this test descriptor may also be a test.
+ *
+ * The implementation must be consistent with {@link #getType()} such
+ * that {@code x.isContainer()} equals {@code x.getType().isContainer()}.
*
* The default implementation delegates to {@link Type#isContainer()}.
*/
@@ -239,7 +264,14 @@ default boolean isContainer() {
}
/**
- * Determine if this descriptor describes a test.
+ * Determine if this descriptor describes a test.
+ *
+ * A test descriptor is a test when it verifies expected
+ * behavior when executed. In addition to being a test this
+ * test descriptor may also be a container.
+ *
+ * The implementation must be consistent with {@link #getType()} such
+ * that {@code x.isTest()} equals {@code x.getType().isTest()}.
*
* The default implementation delegates to {@link Type#isTest()}.
*/
@@ -250,6 +282,10 @@ default boolean isTest() {
/**
* Determine if this descriptor may register dynamic tests during execution.
*
+ * The implementation must treat this property as immutable after test
+ * discovery has completed and must be consistent with {@link #isContainer()}
+ * such that {@code !x.container()} implies {@code !x.mayRegisterTests()}.
+ *
* The default implementation assumes tests are usually known during
* discovery and thus returns {@code false}.
*/
@@ -259,7 +295,7 @@ default boolean mayRegisterTests() {
/**
* Determine if the supplied descriptor (or any of its descendants)
- * {@linkplain TestDescriptor#isTest() is a test} or
+ * {@linkplain TestDescriptor#isTest() is a test} or
* {@linkplain TestDescriptor#mayRegisterTests() may potentially register
* tests dynamically}.
*
@@ -355,12 +391,14 @@ static Visitor composite(Visitor... visitors) {
enum Type {
/**
- * Denotes that the {@link TestDescriptor} is for a container.
+ * Denotes that the {@link TestDescriptor} is strictly for a
+ * container. I.e. it is not also a test.
*/
CONTAINER,
/**
- * Denotes that the {@link TestDescriptor} is for a test.
+ * Denotes that the {@link TestDescriptor} is strictly for a
+ * test. I.e. it is not also a container.
*/
TEST,