diff --git a/documentation/src/docs/asciidoc/release-notes/release-notes-6.0.0-RC3.adoc b/documentation/src/docs/asciidoc/release-notes/release-notes-6.0.0-RC3.adoc index fae30bcd5f32..75ce7de79cb4 100644 --- a/documentation/src/docs/asciidoc/release-notes/release-notes-6.0.0-RC3.adoc +++ b/documentation/src/docs/asciidoc/release-notes/release-notes-6.0.0-RC3.adoc @@ -38,6 +38,9 @@ JUnit repository on GitHub. * New `Resource.from(String, URI)` static factory method for creating an `org.junit.platform.commons.support.Resource`. +* New `FileSource.withPosition(FilePosition)` method to avoid the overhead of redundant + canonicalization of files when using `FileSource.from(File, FilePosition)` with many + different `FilePosition` instances for the same `File`. [[release-notes-6.0.0-RC3-junit-jupiter]] diff --git a/junit-platform-engine/src/main/java/org/junit/platform/engine/support/descriptor/FileSource.java b/junit-platform-engine/src/main/java/org/junit/platform/engine/support/descriptor/FileSource.java index 6e7a3ac95452..ad869d878b5c 100644 --- a/junit-platform-engine/src/main/java/org/junit/platform/engine/support/descriptor/FileSource.java +++ b/junit-platform-engine/src/main/java/org/junit/platform/engine/support/descriptor/FileSource.java @@ -10,6 +10,7 @@ package org.junit.platform.engine.support.descriptor; +import static org.apiguardian.api.API.Status.EXPERIMENTAL; import static org.apiguardian.api.API.Status.STABLE; import java.io.File; @@ -53,6 +54,7 @@ public static FileSource from(File file) { * * @param file the source file; must not be {@code null} * @param filePosition the position in the source file; may be {@code null} + * @see #withPosition(FilePosition) */ public static FileSource from(File file, @Nullable FilePosition filePosition) { return new FileSource(file, filePosition); @@ -77,6 +79,11 @@ private FileSource(File file, @Nullable FilePosition filePosition) { this.filePosition = filePosition; } + private FileSource(FileSource fileSource, @Nullable FilePosition filePosition) { + this.file = fileSource.file; + this.filePosition = filePosition; + } + /** * Get the {@link URI} for the source {@linkplain #getFile file}. * @@ -104,6 +111,30 @@ public Optional getPosition() { return Optional.ofNullable(this.filePosition); } + /** + * {@return a {@code FileSource} based on this instance but with the + * supplied {@link FilePosition}} + * + *

If the supplied {@code FilePosition} + * {@linkplain Objects#equals(Object, Object) equals} the existing one, this + * method returns {@code this}. Otherwise, a new instance is created and + * returned. + * + *

Calling this method rather than creating a new {@code FileSource} via + * {@link #from(File, FilePosition)} avoids the overhead of redundant + * canonical path resolution. + * + * @param filePosition the position in the source file; may be {@code null} + * @since 6.0 + */ + @API(status = EXPERIMENTAL, since = "6.0") + public FileSource withPosition(@Nullable FilePosition filePosition) { + if (Objects.equals(this.filePosition, filePosition)) { + return this; + } + return new FileSource(this, filePosition); + } + @Override public boolean equals(Object o) { if (this == o) { diff --git a/platform-tests/src/test/java/org/junit/platform/engine/support/descriptor/FileSystemSourceTests.java b/platform-tests/src/test/java/org/junit/platform/engine/support/descriptor/FileSystemSourceTests.java index 802d2c47cda6..b05bae70d7b5 100644 --- a/platform-tests/src/test/java/org/junit/platform/engine/support/descriptor/FileSystemSourceTests.java +++ b/platform-tests/src/test/java/org/junit/platform/engine/support/descriptor/FileSystemSourceTests.java @@ -76,6 +76,27 @@ void fileWithPosition() { assertThat(source.getPosition()).hasValue(position); } + @Test + void fileReuseWithPosition() { + var file = new File("test.txt"); + var position = FilePosition.from(42, 23); + var source = FileSource.from(file); + var sourceWithPosition = source.withPosition(position); + + assertThat(source.getUri()).isEqualTo(file.getAbsoluteFile().toURI()); + assertThat(source.getFile()).isEqualTo(file.getAbsoluteFile()); + assertThat(source.getPosition()).isEmpty(); + + assertThat(source).isNotSameAs(sourceWithPosition); + assertThat(source.getFile()).isSameAs(sourceWithPosition.getFile()); + assertThat(sourceWithPosition.getPosition()).hasValue(position); + + assertThat(sourceWithPosition.withPosition(null).getPosition()).isEmpty(); + + assertThat(source.withPosition(null)).isSameAs(source); + assertThat(sourceWithPosition.withPosition(position)).isSameAs(sourceWithPosition); + } + @Test void equalsAndHashCodeForFileSource() { var file1 = new File("foo.txt");