Skip to content

Commit ce19e3b

Browse files
authored
[Core] Replace ResourceIterable with standard Java solutions (#1820)
`ResourceIterable` provides inconsistent support for URI's. Supported: * file:path/to.feature * classpath:com/example.feature * classpath:features.jar#!com/example.feature Unsupported: * jar:path/to.jar#!/com/example.feature * any-jvm-supported-file-system:path/to.feature Replacing `ResourceIterable` with `FileSystem` and `Path` adds consistent support for URI's and reduces the complexity of scanning for classes and resources significantly. Both `ClasspathScanner` and `ResourceScanner` are instantiated with a ClassLoader for all class path operations. This should allow Cucumber access to platforms use fat jars and other packaging methods. Fixes: #1526
1 parent 556fb3d commit ce19e3b

File tree

115 files changed

+1635
-1899
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

115 files changed

+1635
-1899
lines changed

core/src/main/java/cucumber/api/cli/Main.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ public static void main(String[] argv) {
2424
* @return 0 if execution was successful, 1 if it was not (test failures)
2525
*/
2626
public static byte run(String[] argv, ClassLoader classLoader) {
27-
log.warn("You are using deprecated Main class. Please use io.cucumber.core.cli.Main");
27+
log.warn(() -> "You are using deprecated Main class. Please use io.cucumber.core.cli.Main");
2828
return io.cucumber.core.cli.Main.run(argv, classLoader);
2929
}
3030
}

core/src/main/java/io/cucumber/core/cli/Main.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ public static byte run(String[] argv, ClassLoader classLoader) {
5757

5858
final Runtime runtime = Runtime.builder()
5959
.withRuntimeOptions(runtimeOptions)
60-
.withClassLoader(classLoader)
60+
.withClassLoader(() -> classLoader)
6161
.build();
6262

6363
runtime.run();

core/src/main/java/io/cucumber/core/feature/CucumberPickle.java

+18-3
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,15 @@ public String getName() {
6262
* @return line in the feature file
6363
*/
6464
public int getLine() {
65-
return pickle.getLocations().get(0).getLine();
65+
return getPickleLocation().getLine();
66+
}
67+
68+
public int getColumn() {
69+
return getPickleLocation().getColumn();
70+
}
71+
72+
private PickleLocation getPickleLocation() {
73+
return pickle.getLocations().get(0);
6674
}
6775

6876
/**
@@ -72,8 +80,16 @@ public int getLine() {
7280
* @return line in the feature file
7381
*/
7482
public int getScenarioLine() {
83+
return getScenarioLocation().getLine();
84+
}
85+
86+
public int getScenarioColumn(){
87+
return getScenarioLocation().getColumn();
88+
}
89+
90+
private PickleLocation getScenarioLocation() {
7591
List<PickleLocation> stepLocations = pickle.getLocations();
76-
return stepLocations.get(stepLocations.size() - 1).getLine();
92+
return stepLocations.get(stepLocations.size() - 1);
7793
}
7894

7995
public List<CucumberStep> getSteps() {
@@ -88,5 +104,4 @@ public URI getUri() {
88104
return uri;
89105
}
90106

91-
92107
}

core/src/main/java/io/cucumber/core/feature/Encoding.java

+8-4
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,18 @@
11
package io.cucumber.core.feature;
22

3-
import io.cucumber.core.io.Resource;
3+
import io.cucumber.core.resource.Resource;
44

55
import java.io.BufferedReader;
66
import java.io.IOException;
7+
import java.io.InputStream;
78
import java.io.InputStreamReader;
89
import java.util.regex.Matcher;
910
import java.util.regex.Pattern;
10-
import java.util.stream.Collectors;
1111

12+
import static java.lang.System.lineSeparator;
1213
import static java.nio.charset.StandardCharsets.UTF_8;
1314
import static java.util.Locale.ROOT;
15+
import static java.util.stream.Collectors.joining;
1416

1517
/**
1618
* Utilities for reading the encoding of a file.
@@ -35,8 +37,10 @@ static String readFile(Resource resource) throws RuntimeException, IOException {
3537
}
3638

3739
private static String read(Resource resource, String encoding) throws IOException {
38-
try(BufferedReader br = new BufferedReader(new InputStreamReader(resource.getInputStream(), encoding))){
39-
return br.lines().collect(Collectors.joining(System.lineSeparator()));
40+
try (InputStream is = resource.getInputStream()) {
41+
InputStreamReader in = new InputStreamReader(is, encoding);
42+
BufferedReader reader = new BufferedReader(in);
43+
return reader.lines().collect(joining(lineSeparator()));
4044
}
4145
}
4246

core/src/main/java/io/cucumber/core/feature/FeatureBuilder.java

-61
This file was deleted.

core/src/main/java/io/cucumber/core/feature/FeatureIdentifier.java

+4
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package io.cucumber.core.feature;
22
import java.net.URI;
3+
import java.nio.file.Path;
34

45
/**
56
* Identifies a single feature.
@@ -30,4 +31,7 @@ public static boolean isFeature(URI featureIdentifier) {
3031
return featureIdentifier.getSchemeSpecificPart().endsWith(".feature");
3132
}
3233

34+
public static boolean isFeature(Path path) {
35+
return path.getFileName().toString().endsWith(".feature");
36+
}
3337
}

core/src/main/java/io/cucumber/core/feature/FeatureLoader.java

-39
This file was deleted.

core/src/main/java/io/cucumber/core/feature/FeatureParser.java

+6-6
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
import gherkin.ast.GherkinDocument;
1010
import gherkin.pickles.Compiler;
1111
import io.cucumber.core.exception.CucumberException;
12-
import io.cucumber.core.io.Resource;
12+
import io.cucumber.core.resource.Resource;
1313

1414
import java.io.IOException;
1515
import java.net.URI;
@@ -26,7 +26,7 @@ private FeatureParser() {
2626

2727
public static CucumberFeature parseResource(Resource resource) {
2828
requireNonNull(resource);
29-
URI path = resource.getPath();
29+
URI uri = resource.getUri();
3030
String source = read(resource);
3131

3232
try {
@@ -35,17 +35,17 @@ public static CucumberFeature parseResource(Resource resource) {
3535
GherkinDocument gherkinDocument = parser.parse(source, matcher);
3636
GherkinDialectProvider dialectProvider = new GherkinDialectProvider();
3737
List<CucumberPickle> pickles = compilePickles(gherkinDocument, dialectProvider, resource);
38-
return new CucumberFeature(gherkinDocument, path, source, pickles);
38+
return new CucumberFeature(gherkinDocument, uri, source, pickles);
3939
} catch (ParserException e) {
40-
throw new CucumberException("Failed to parse resource at: " + path.toString(), e);
40+
throw new CucumberException("Failed to parse resource at: " + uri.toString(), e);
4141
}
4242
}
4343

4444
private static String read(Resource resource) {
4545
try {
4646
return Encoding.readFile(resource);
4747
} catch (IOException e) {
48-
throw new CucumberException("Failed to read resource:" + resource.getPath(), e);
48+
throw new CucumberException("Failed to read resource:" + resource.getUri(), e);
4949
}
5050
}
5151

@@ -58,7 +58,7 @@ private static List<CucumberPickle> compilePickles(GherkinDocument document, Ghe
5858
GherkinDialect dialect = dialectProvider.getDialect(language, null);
5959
return new Compiler().compile(document)
6060
.stream()
61-
.map(pickle -> new CucumberPickle(pickle, resource.getPath(), document, dialect))
61+
.map(pickle -> new CucumberPickle(pickle, resource.getUri(), document, dialect))
6262
.collect(Collectors.toList());
6363
}
6464
}

core/src/main/java/io/cucumber/core/feature/FeaturePath.java

+16-32
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,10 @@
22

33
import java.io.File;
44
import java.net.URI;
5-
import java.net.URISyntaxException;
65
import java.util.Locale;
76

8-
import static io.cucumber.core.io.Classpath.CLASSPATH_SCHEME;
9-
import static io.cucumber.core.io.Classpath.CLASSPATH_SCHEME_PREFIX;
7+
import static io.cucumber.core.resource.ClasspathSupport.CLASSPATH_SCHEME_PREFIX;
8+
import static io.cucumber.core.resource.ClasspathSupport.rootPackage;
109
import static java.util.Objects.requireNonNull;
1110

1211
/**
@@ -33,21 +32,21 @@ private FeaturePath() {
3332

3433
public static URI parse(String featureIdentifier) {
3534
requireNonNull(featureIdentifier, "featureIdentifier may not be null");
36-
if(featureIdentifier.isEmpty()){
35+
if (featureIdentifier.isEmpty()) {
3736
throw new IllegalArgumentException("featureIdentifier may not be empty");
3837
}
3938

4039
// Legacy from the Cucumber Eclipse plugin
4140
// Older versions of Cucumber allowed it.
42-
if(CLASSPATH_SCHEME_PREFIX.equals(featureIdentifier)){
41+
if (CLASSPATH_SCHEME_PREFIX.equals(featureIdentifier)) {
4342
return rootPackage();
4443
}
4544

4645
if (nonStandardPathSeparatorInUse(featureIdentifier)) {
4746
String standardized = replaceNonStandardPathSeparator(featureIdentifier);
4847
return parseAssumeFileScheme(standardized);
4948
}
50-
49+
5150
if (isWindowsOS() && pathContainsWindowsDrivePattern(featureIdentifier)) {
5251
return parseAssumeFileScheme(featureIdentifier);
5352
}
@@ -59,27 +58,23 @@ public static URI parse(String featureIdentifier) {
5958
return parseAssumeFileScheme(featureIdentifier);
6059
}
6160

62-
private static URI rootPackage() {
63-
try {
64-
return new URI(CLASSPATH_SCHEME, "/" ,null);
65-
} catch (URISyntaxException e) {
66-
throw new IllegalArgumentException(e);
61+
private static URI parseProbableURI(String featureIdentifier) {
62+
URI uri = URI.create(featureIdentifier);
63+
if ("file".equals(uri.getScheme())) {
64+
return parseAssumeFileScheme(uri.getSchemeSpecificPart());
6765
}
66+
return uri;
6867
}
6968

70-
private static URI parseProbableURI(String featureIdentifier) {
71-
return URI.create(featureIdentifier);
72-
}
73-
74-
private static boolean isWindowsOS() {
69+
private static boolean isWindowsOS() {
7570
String osName = System.getProperty("os.name");
7671
return normalize(osName).contains("windows");
7772
}
78-
73+
7974
private static boolean pathContainsWindowsDrivePattern(String featureIdentifier) {
8075
return featureIdentifier.matches("^[a-zA-Z]:.*$");
8176
}
82-
77+
8378
private static boolean probablyURI(String featureIdentifier) {
8479
return featureIdentifier.matches("^[a-zA-Z+.\\-]+:.*$");
8580
}
@@ -94,25 +89,14 @@ private static boolean nonStandardPathSeparatorInUse(String featureIdentifier) {
9489

9590
private static URI parseAssumeFileScheme(String featureIdentifier) {
9691
File featureFile = new File(featureIdentifier);
97-
if (featureFile.isAbsolute()) {
98-
return featureFile.toURI();
99-
}
100-
101-
try {
102-
URI root = new File("").toURI();
103-
URI relative = root.relativize(featureFile.toURI());
104-
// Scheme is lost by relativize
105-
return new URI("file", relative.getSchemeSpecificPart(), relative.getFragment());
106-
} catch (URISyntaxException e) {
107-
throw new IllegalArgumentException(e.getMessage(), e);
108-
}
92+
return featureFile.toURI();
10993
}
110-
94+
11195
private static String normalize(final String value) {
11296
if (value == null) {
11397
return "";
11498
}
11599
return value.toLowerCase(Locale.US).replaceAll("[^a-z0-9]+", "");
116100
}
117-
101+
118102
}

0 commit comments

Comments
 (0)