diff --git a/documentation/src/docs/asciidoc/release-notes/release-notes-5.11.0-M2.adoc b/documentation/src/docs/asciidoc/release-notes/release-notes-5.11.0-M2.adoc index 06f97c9d06da..a30af74add41 100644 --- a/documentation/src/docs/asciidoc/release-notes/release-notes-5.11.0-M2.adoc +++ b/documentation/src/docs/asciidoc/release-notes/release-notes-5.11.0-M2.adoc @@ -26,6 +26,7 @@ repository on GitHub. [[release-notes-5.11.0-M2-junit-platform-bug-fixes]] ==== Bug Fixes +* Fixed a bug where `TestIdentifier` could cause a `NullPointerException` on deserialize when there is no parent identifier. See link:/~https://github.com/junit-team/junit5/issues/3819[issue 3819]. * ❓ [[release-notes-5.11.0-M2-junit-platform-deprecations-and-breaking-changes]] diff --git a/junit-platform-launcher/src/main/java/org/junit/platform/launcher/TestIdentifier.java b/junit-platform-launcher/src/main/java/org/junit/platform/launcher/TestIdentifier.java index 4a331d6e50b3..ae3cd416469e 100644 --- a/junit-platform-launcher/src/main/java/org/junit/platform/launcher/TestIdentifier.java +++ b/junit-platform-launcher/src/main/java/org/junit/platform/launcher/TestIdentifier.java @@ -284,7 +284,8 @@ private void readObject(ObjectInputStream s) throws ClassNotFoundException, IOEx source = serializedForm.source; tags = serializedForm.tags; type = serializedForm.type; - parentId = UniqueId.parse(serializedForm.parentId); + String parentId = serializedForm.parentId; + this.parentId = parentId == null ? null : UniqueId.parse(parentId); legacyReportingName = serializedForm.legacyReportingName; } @@ -307,7 +308,8 @@ private static class SerializedForm implements Serializable { SerializedForm(TestIdentifier testIdentifier) { this.uniqueId = testIdentifier.uniqueId.toString(); - this.parentId = testIdentifier.parentId.toString(); + UniqueId parentId = testIdentifier.parentId; + this.parentId = parentId == null ? null : parentId.toString(); this.displayName = testIdentifier.displayName; this.legacyReportingName = testIdentifier.legacyReportingName; this.source = testIdentifier.source; diff --git a/platform-tests/src/test/java/org/junit/platform/launcher/TestIdentifierTests.java b/platform-tests/src/test/java/org/junit/platform/launcher/TestIdentifierTests.java index d971eb7a8e63..3be24b6d02ea 100644 --- a/platform-tests/src/test/java/org/junit/platform/launcher/TestIdentifierTests.java +++ b/platform-tests/src/test/java/org/junit/platform/launcher/TestIdentifierTests.java @@ -16,10 +16,12 @@ import static org.junit.platform.commons.util.SerializationUtils.deserialize; import static org.junit.platform.commons.util.SerializationUtils.serialize; +import java.util.Optional; import java.util.Set; import org.junit.jupiter.api.Test; import org.junit.platform.engine.TestDescriptor; +import org.junit.platform.engine.TestSource; import org.junit.platform.engine.TestTag; import org.junit.platform.engine.UniqueId; import org.junit.platform.engine.support.descriptor.AbstractTestDescriptor; @@ -72,6 +74,74 @@ void initialVersionCanBeDeserialized() throws Exception { } } + @Test + void identifierWithNoParentCanBeSerializedAndDeserialized() throws Exception { + TestIdentifier ti = TestIdentifier.from(new TestDescriptor() { + @Override + public UniqueId getUniqueId() { + return UniqueId.root("example", "id"); + } + + @Override + public String getDisplayName() { + return "displayName"; + } + + @Override + public Set getTags() { + return Set.of(); + } + + @Override + public Optional getSource() { + return Optional.empty(); + } + + @Override + public Optional getParent() { + return Optional.empty(); + } + + @Override + public void setParent(TestDescriptor parent) { + // ignore + } + + @Override + public Set getChildren() { + return Set.of(); + } + + @Override + public void addChild(TestDescriptor descriptor) { + // ignore + } + + @Override + public void removeChild(TestDescriptor descriptor) { + // ignore + } + + @Override + public void removeFromHierarchy() { + // ignore + } + + @Override + public Type getType() { + return Type.TEST; + } + + @Override + public Optional findByUniqueId(UniqueId uniqueId) { + return Optional.empty(); + } + }); + byte[] bytes = serialize(ti); + TestIdentifier dti = (TestIdentifier) deserialize(bytes); + assertEquals(ti, dti); + } + private static void assertDeepEquals(TestIdentifier first, TestIdentifier second) { assertEquals(first, second); assertEquals(first.getUniqueId(), second.getUniqueId());