Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add FilePosition in FileSelector and ClasspathResourceSelector #2253

Merged
merged 29 commits into from
May 22, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
49b8684
Support FilePosition in FileSelector & ClasspathResourceSelector
Apr 5, 2020
a65fb00
Add JavaDoc
Apr 5, 2020
6d8fe26
Add constructor unit tests
Apr 5, 2020
612df8e
Move, duplicate & deprecate FilePosition as suggested
Apr 10, 2020
71130a6
Move FilePositionTests and have it extend AbstractEqualsAndHashCodeTests
Apr 10, 2020
2c5ece1
Add FileSelector DiscoverySelectors with arguments for line and column
Apr 10, 2020
95557dd
Cover selectFile and selectClasspathResource with file position
Apr 10, 2020
1202335
Add position in toString
Apr 10, 2020
98a361a
Apply spotless
Apr 10, 2020
f8b14c1
Address review comments regarding FilePosition classes
Apr 10, 2020
092ff61
Optional return types for nullable position
Apr 10, 2020
2520537
Take FilePosition as argument in DiscoverySelectors as suggested
Apr 10, 2020
fb9cec7
Adapt tests to use FilePosition arguments and Optional return types
Apr 10, 2020
decb669
Adopt public static Optional<? extends FilePosition> fromQuery in parent
Apr 10, 2020
a768cf4
Add alternative getFilePosition() and restore getPosition() return type
Apr 11, 2020
dd3d8f7
Deprecate FileSource/ClasspathResourceSource getPosition() methods
Apr 11, 2020
f80fcb9
Also restore original arguments to Source from methods
Apr 11, 2020
147ea9d
Restore original argument to ClassSource.from method
Apr 11, 2020
528ea87
Merge branch 'master' of github.com:junit-team/junit5
May 2, 2020
0a14c1b
Revert changes to org.junit.platform.engine.support.descriptor package
May 2, 2020
5baa390
Create a copy of FilePosition without further modifier/generics changes
May 2, 2020
e996f17
Make FilePosition fields in Selectors final
May 2, 2020
28cbaea
Update release notes
May 2, 2020
296cddb
Merge branch 'master' into master
timtebeek May 6, 2020
267ef71
Apply suggestions from code review
May 16, 2020
40bc12a
Delegate selectFile/selectClasspath methods to copy with FilePosition
May 16, 2020
50ba225
Remove constructors without FilePosition; Update tests to match
May 16, 2020
1910558
Separate tests for DiscoverySelectors with FilePosition argument
May 16, 2020
2fbc96d
Update platform-tests/src/test/java/org/junit/platform/engine/discove…
May 16, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ on GitHub.
* When using `ConsoleLauncher`, explicitly selected classes from `--select-class`
and `--select-method` are now always executed regardless of class name patterns
provided with `--include-classname` or the default class name pattern.

* Support `FilePosition` in `FileSelector` and `ClasspathResourceSelector`.

[[release-notes-5.7.0-M2-junit-jupiter]]
=== JUnit Jupiter
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
import static org.apiguardian.api.API.Status.STABLE;

import java.util.Objects;
import java.util.Optional;

import org.apiguardian.api.API;
import org.junit.platform.commons.util.ToStringBuilder;
Expand All @@ -39,10 +40,12 @@
public class ClasspathResourceSelector implements DiscoverySelector {

private final String classpathResourceName;
private final FilePosition position;

ClasspathResourceSelector(String classpathResourceName) {
ClasspathResourceSelector(String classpathResourceName, FilePosition position) {
boolean startsWithSlash = classpathResourceName.startsWith("/");
this.classpathResourceName = (startsWithSlash ? classpathResourceName.substring(1) : classpathResourceName);
this.position = position;
}

/**
Expand All @@ -59,6 +62,13 @@ public String getClasspathResourceName() {
return this.classpathResourceName;
}

/**
* Get the selected {@code FilePosition} within the classpath resource.
*/
public Optional<FilePosition> getPosition() {
return Optional.ofNullable(this.position);
}

/**
* @since 1.3
*/
Expand All @@ -72,7 +82,8 @@ public boolean equals(Object o) {
return false;
}
ClasspathResourceSelector that = (ClasspathResourceSelector) o;
return Objects.equals(this.classpathResourceName, that.classpathResourceName);
return Objects.equals(this.classpathResourceName, that.classpathResourceName)
&& Objects.equals(this.position, that.position);
}

/**
Expand All @@ -81,12 +92,13 @@ public boolean equals(Object o) {
@API(status = STABLE, since = "1.3")
@Override
public int hashCode() {
return this.classpathResourceName.hashCode();
return Objects.hash(this.classpathResourceName, this.position);
}

@Override
public String toString() {
return new ToStringBuilder(this).append("classpathResourceName", this.classpathResourceName).toString();
return new ToStringBuilder(this).append("classpathResourceName", this.classpathResourceName).append("position",
this.position).toString();
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -102,12 +102,12 @@ public static UriSelector selectUri(URI uri) {
* @param path the path to the file to select; never {@code null} or blank
* @see FileSelector
* @see #selectFile(File)
* @see #selectFile(String, FilePosition)
* @see #selectDirectory(String)
* @see #selectDirectory(File)
*/
public static FileSelector selectFile(String path) {
Preconditions.notBlank(path, "File path must not be null or blank");
return new FileSelector(path);
return selectFile(path, null);
}

/**
Expand All @@ -120,15 +120,54 @@ public static FileSelector selectFile(String path) {
* @param file the file to select; never {@code null}
* @see FileSelector
* @see #selectFile(String)
* @see #selectFile(File, FilePosition)
* @see #selectDirectory(String)
* @see #selectDirectory(File)
*/
public static FileSelector selectFile(File file) {
return selectFile(file, null);
}

/**
* Create a {@code FileSelector} for the supplied file path.
*
* <p>This method selects the file using the supplied path <em>as is</em>,
* without verifying if the file exists.
*
* @param path the path to the file to select; never {@code null} or blank
* @param position the position inside the file; may be {@code null}
* @see FileSelector
* @see #selectFile(String)
* @see #selectFile(File, FilePosition)
* @see #selectDirectory(String)
* @see #selectDirectory(File)
*/
public static FileSelector selectFile(String path, FilePosition position) {
Preconditions.notBlank(path, "File path must not be null or blank");
return new FileSelector(path, position);
}

/**
* Create a {@code FileSelector} for the supplied {@linkplain File file}.
*
* <p>This method selects the file in its {@linkplain File#getCanonicalPath()
* canonical} form and throws a {@link PreconditionViolationException} if the
* file does not exist.
*
* @param file the file to select; never {@code null}
* @param position the position inside the file; may be {@code null}
* @see FileSelector
* @see #selectFile(File)
* @see #selectFile(String, FilePosition)
* @see #selectDirectory(String)
* @see #selectDirectory(File)
*/
public static FileSelector selectFile(File file, FilePosition position) {
timtebeek marked this conversation as resolved.
Show resolved Hide resolved
Preconditions.notNull(file, "File must not be null");
Preconditions.condition(file.isFile(),
() -> String.format("The supplied java.io.File [%s] must represent an existing file", file));
try {
return new FileSelector(file.getCanonicalPath());
return new FileSelector(file.getCanonicalPath(), position);
}
catch (IOException ex) {
throw new PreconditionViolationException("Failed to retrieve canonical path for file: " + file, ex);
Expand Down Expand Up @@ -232,14 +271,44 @@ public static List<ClasspathRootSelector> selectClasspathRoots(Set<Path> classpa
*
* @param classpathResourceName the name of the classpath resource; never
* {@code null} or blank
* @see #selectClasspathResource(String, FilePosition)
* @see ClasspathResourceSelector
* @see ClassLoader#getResource(String)
* @see ClassLoader#getResourceAsStream(String)
* @see ClassLoader#getResources(String)
*/
public static ClasspathResourceSelector selectClasspathResource(String classpathResourceName) {
return selectClasspathResource(classpathResourceName, null);
}

/**
* Create a {@code ClasspathResourceSelector} for the supplied classpath
* resource name.
*
* <p>The name of a <em>classpath resource</em> must follow the semantics
* for resource paths as defined in {@link ClassLoader#getResource(String)}.
*
* <p>If the supplied classpath resource name is prefixed with a slash
* ({@code /}), the slash will be removed.
*
* <p>Since {@linkplain org.junit.platform.engine.TestEngine engines} are not
* expected to modify the classpath, the supplied classpath resource must be
* on the classpath of the
* {@linkplain Thread#getContextClassLoader() context class loader} of the
* {@linkplain Thread thread} that uses the resulting selector.
*
* @param classpathResourceName the name of the classpath resource; never
* {@code null} or blank
* @param position the position inside the classpath resource; may be {@code null}
* @see ClasspathResourceSelector
* @see ClassLoader#getResource(String)
* @see ClassLoader#getResourceAsStream(String)
* @see ClassLoader#getResources(String)
*/
public static ClasspathResourceSelector selectClasspathResource(String classpathResourceName,
FilePosition position) {
Preconditions.notBlank(classpathResourceName, "Classpath resource name must not be null or blank");
return new ClasspathResourceSelector(classpathResourceName);
return new ClasspathResourceSelector(classpathResourceName, position);
}

/**
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,178 @@
/*
* Copyright 2015-2020 the original author or authors.
*
* All rights reserved. This program and the accompanying materials are
* made available under the terms of the Eclipse Public License v2.0 which
* accompanies this distribution and is available at
*
* https://www.eclipse.org/legal/epl-v20.html
*/

package org.junit.platform.engine.discovery;

import static org.apiguardian.api.API.Status.STABLE;

import java.io.Serializable;
import java.util.Objects;
import java.util.Optional;

import org.apiguardian.api.API;
import org.junit.platform.commons.logging.Logger;
import org.junit.platform.commons.logging.LoggerFactory;
import org.junit.platform.commons.util.Preconditions;
import org.junit.platform.commons.util.StringUtils;
import org.junit.platform.commons.util.ToStringBuilder;

/**
* Position inside a file represented by {@linkplain #getLine line} and
* {@linkplain #getColumn column} numbers.
*
* @since 1.7
*/
@API(status = STABLE, since = "1.7")
public class FilePosition implements Serializable {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@junit-team/junit-lambda Should we mention in the Javadoc that this class is actually a copy of descriptor.FilePosition?


private static final long serialVersionUID = 1L;

private static final Logger logger = LoggerFactory.getLogger(FilePosition.class);

/**
* Create a new {@code FilePosition} using the supplied {@code line} number
* and an undefined column number.
*
* @param line the line number; must be greater than zero
* @return a {@link FilePosition} with the given line number
*/
public static FilePosition from(int line) {
return new FilePosition(line);
}

/**
* Create a new {@code FilePosition} using the supplied {@code line} and
* {@code column} numbers.
*
* @param line the line number; must be greater than zero
* @param column the column number; must be greater than zero
* @return a {@link FilePosition} with the given line and column numbers
*/
public static FilePosition from(int line, int column) {
return new FilePosition(line, column);
}

/**
* Create an optional {@code FilePosition} by parsing the supplied
* {@code query} string.
*
* <p>Examples of valid {@code query} strings:
* <ul>
* <li>{@code "line=23"}</li>
* <li>{@code "line=23&column=42"}</li>
* </ul>
*
* @param query the query string; may be {@code null}
* @return an {@link Optional} containing a {@link FilePosition} with
* the parsed line and column numbers; never {@code null} but potentially
* empty
* @since 1.3
* @see #from(int)
* @see #from(int, int)
*/
public static Optional<FilePosition> fromQuery(String query) {
FilePosition result = null;
Integer line = null;
Integer column = null;
if (StringUtils.isNotBlank(query)) {
try {
for (String pair : query.split("&")) {
String[] data = pair.split("=");
if (data.length == 2) {
String key = data[0];
if (line == null && "line".equals(key)) {
line = Integer.valueOf(data[1]);
}
else if (column == null && "column".equals(key)) {
column = Integer.valueOf(data[1]);
}
}

// Already found what we're looking for?
if (line != null && column != null) {
break;
}
}
}
catch (IllegalArgumentException ex) {
logger.debug(ex, () -> "Failed to parse 'line' and/or 'column' from query string: " + query);
// fall-through and continue
}

if (line != null) {
result = column == null ? new FilePosition(line) : new FilePosition(line, column);
}
}
return Optional.ofNullable(result);
}

private final int line;
private final Integer column;

private FilePosition(int line) {
Preconditions.condition(line > 0, "line number must be greater than zero");
this.line = line;
this.column = null;
}

private FilePosition(int line, int column) {
Preconditions.condition(line > 0, "line number must be greater than zero");
Preconditions.condition(column > 0, "column number must be greater than zero");
this.line = line;
this.column = column;
}

/**
* Get the line number of this {@code FilePosition}.
*
* @return the line number
*/
public int getLine() {
return this.line;
}

/**
* Get the column number of this {@code FilePosition}, if available.
*
* @return an {@code Optional} containing the column number; never
* {@code null} but potentially empty
*/
public Optional<Integer> getColumn() {
return Optional.ofNullable(this.column);
}

@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
FilePosition that = (FilePosition) o;
return (this.line == that.line) && Objects.equals(this.column, that.column);
}

@Override
public int hashCode() {
return Objects.hash(this.line, this.column);
}

@Override
public String toString() {
// @formatter:off
return new ToStringBuilder(this)
.append("line", this.line)
.append("column", getColumn().orElse(-1))
.toString();
// @formatter:on
}

}
Loading