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

[JUnit Platform] Use EngineDiscoveryRequestResolver #2835

Draft
wants to merge 33 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from 17 commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
47d345c
[JUnit Platform] Use EngineDiscoveryRequestResolver
mpkorstanje Dec 16, 2023
4ea85b3
WIP
mpkorstanje Jan 4, 2024
bd9ac67
WIP
mpkorstanje Jan 4, 2024
b39764c
WIP
mpkorstanje Feb 15, 2024
9440631
Merge branch 'main' into junit-platform-refactor
mpkorstanje Feb 20, 2024
b6ab3cb
Fix formating
mpkorstanje Feb 20, 2024
b78dac7
WIP
mpkorstanje Feb 20, 2024
15c7221
Merge remote-tracking branch 'origin/main' into junit-platform-refactor
mpkorstanje Jun 13, 2024
c5be199
Fix
mpkorstanje Jun 13, 2024
4596d74
Fix sorting
mpkorstanje Jun 13, 2024
294d880
Clean up
mpkorstanje Jun 13, 2024
17a2881
Merge remote-tracking branch 'origin/main' into junit-platform-refactor
mpkorstanje Sep 5, 2024
5f2ca2f
Merge remote-tracking branch 'origin/main' into junit-platform-refactor
mpkorstanje Oct 31, 2024
9002a1f
WIP
mpkorstanje Oct 31, 2024
a68cc19
Extract FeaturesPropertyResolver
mpkorstanje Nov 1, 2024
ac85314
Refactor tests
mpkorstanje Nov 2, 2024
ff5c6d7
Notes
mpkorstanje Nov 2, 2024
300b405
Simplify
mpkorstanje Nov 6, 2024
1a9e1a7
Move tests for tags to CucumberTestEngineTest
mpkorstanje Nov 6, 2024
26b42ca
Move more tests to CucumberTestEngineTest
mpkorstanje Nov 7, 2024
c090dad
Make it look more like Junit
mpkorstanje Nov 8, 2024
4315b80
Instantiate Configuration exactly once
mpkorstanje Nov 8, 2024
daa5eb4
Merge remote-tracking branch 'origin/main' into junit-platform-refactor
mpkorstanje Nov 21, 2024
a0f84f1
Warn when selectClasspathResource is incorrectly used
mpkorstanje Nov 21, 2024
5c6b17e
Clean up
mpkorstanje Nov 21, 2024
117e1de
Update CHANGELOG
mpkorstanje Nov 24, 2024
514040e
Merge remote-tracking branch 'origin/main' into junit-platform-refactor
mpkorstanje Jan 16, 2025
abb234c
Remove unused code
mpkorstanje Jan 16, 2025
a54ab73
Merge remote-tracking branch 'origin/main' into junit-platform-refactor
mpkorstanje Jan 30, 2025
9e42cae
Merge remote-tracking branch 'origin/main' into junit-platform-refactor
mpkorstanje Feb 9, 2025
cc1c3f5
Use JUnit 5.12.0-RC1
mpkorstanje Feb 9, 2025
4213749
WIP
mpkorstanje Feb 14, 2025
a724633
Merge remote-tracking branch 'origin/main' into junit-platform-refactor
mpkorstanje Feb 25, 2025
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
7 changes: 6 additions & 1 deletion cucumber-junit-platform-engine/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@

<properties>
<hamcrest.version>3.0</hamcrest.version>
<junit-jupiter.version>5.11.2</junit-jupiter.version>
<junit-jupiter.version>5.12.0-SNAPSHOT</junit-jupiter.version>
</properties>

<dependencyManagement>
Expand Down Expand Up @@ -65,6 +65,11 @@
<artifactId>junit-jupiter-api</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-params</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.platform</groupId>
<artifactId>junit-platform-testkit</artifactId>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
package io.cucumber.junit.platform.engine;

import io.cucumber.core.exception.CucumberException;
import io.cucumber.core.feature.FeatureParser;
import io.cucumber.core.gherkin.Feature;
import io.cucumber.core.resource.Resource;

import java.io.IOException;
import java.io.InputStream;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
Expand All @@ -21,4 +25,32 @@ class CachingFeatureParser {
Optional<Feature> parseResource(Resource resource) {
return cache.computeIfAbsent(resource.getUri(), uri -> delegate.parseResource(resource));
}

Optional<Feature> parseResource(org.junit.platform.commons.support.Resource resource) {
return cache.computeIfAbsent(resource.getUri(), uri -> delegate.parseResource(new ResourceAdapter(resource)));
}

private static class ResourceAdapter implements Resource {
private final org.junit.platform.commons.support.Resource resource;

public ResourceAdapter(org.junit.platform.commons.support.Resource resource) {
this.resource = resource;
}

@Override
public URI getUri() {
String name = resource.getName();
try {
return new URI("classpath", name, null);
} catch (URISyntaxException e) {
String message = String.format("Could not create classpath uri for resource '%s'", name);
throw new CucumberException(message, e);
}
}

@Override
public InputStream getInputStream() throws IOException {
return resource.getInputStream();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,9 @@
* <p>
*
* @deprecated Please use the JUnit Platform Suite to run Cucumber in
* combination with Surefire or Gradle. E.g: <code><pre>{@code
* combination with Surefire or Gradle. E.g:
*
* <pre>{@code
*package com.example;
*
*import org.junit.platform.suite.api.ConfigurationParameter;
Expand All @@ -33,15 +35,15 @@
*
*import static io.cucumber.junit.platform.engine.Constants.GLUE_PROPERTY_NAME;
*
*&#64;Suite
*&#64;SelectPackages("com.example")
*&#64;ConfigurationParameter(
* key = GLUE_PROPERTY_NAME,
* value = "com.example"
*)
*public class RunCucumberTest {
*}
*}</pre></code>
* @Suite
* @SelectPackages("com.example")
* @ConfigurationParameter(
* key = GLUE_PROPERTY_NAME,
* value = "com.example")
* public class RunCucumberTest {
* }
* }</pre>
*
* @see CucumberTestEngine
*/
@API(status = Status.DEPRECATED)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,159 @@
package io.cucumber.junit.platform.engine;

import io.cucumber.core.feature.FeatureWithLines;
import io.cucumber.core.gherkin.Feature;
import io.cucumber.plugin.event.Node;
import org.junit.platform.engine.DiscoverySelector;
import org.junit.platform.engine.UniqueId;
import org.junit.platform.engine.discovery.FilePosition;

import java.net.URI;
import java.util.Collections;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;

import static java.util.Objects.requireNonNull;
import static java.util.stream.Collectors.toSet;

class CucumberDiscoverySelectors {

static final class FeatureWithLinesSelector implements DiscoverySelector {
private final URI uri;
private final Set<FilePosition> filePositions;

private FeatureWithLinesSelector(URI uri, Set<FilePosition> filePositions) {
this.uri = requireNonNull(uri);
this.filePositions = requireNonNull(filePositions);
}

static FeatureWithLinesSelector from(FeatureWithLines featureWithLines) {
Set<FilePosition> lines = featureWithLines.lines().stream()
.map(FilePosition::from)
.collect(Collectors.toSet());
return new FeatureWithLinesSelector(featureWithLines.uri(), lines);
}

static Set<FeatureWithLinesSelector> from(UniqueId uniqueId) {
return uniqueId.getSegments()
.stream()
.filter(FeatureOrigin::isFeatureSegment)
.map(featureSegment -> {
URI uri = URI.create(featureSegment.getValue());
Set<FilePosition> filePosition = getFilePosition(uniqueId.getLastSegment());
return new FeatureWithLinesSelector(uri, filePosition);
})
.collect(Collectors.toSet());
}

static FeatureWithLinesSelector from(URI uri) {
Set<FilePosition> positions = FilePosition.fromQuery(uri.getQuery())
.map(Collections::singleton)
.orElseGet(Collections::emptySet);
return new FeatureWithLinesSelector(stripQuery(uri), positions);
}

private static URI stripQuery(URI uri) {
if (uri.getQuery() == null) {
return uri;
}
String uriString = uri.toString();
return URI.create(uriString.substring(0, uriString.indexOf('?')));
}

private static Set<FilePosition> getFilePosition(UniqueId.Segment segment) {
if (FeatureOrigin.isFeatureSegment(segment)) {
return Collections.emptySet();
}

int line = Integer.parseInt(segment.getValue());
return Collections.singleton(FilePosition.from(line));
}

URI getUri() {
return uri;
}

Optional<Set<FilePosition>> getFilePositions() {
return filePositions.isEmpty() ? Optional.empty() : Optional.of(filePositions);
}

@Override
public boolean equals(Object o) {
if (this == o)
return true;
if (o == null || getClass() != o.getClass())
return false;
FeatureWithLinesSelector that = (FeatureWithLinesSelector) o;
return uri.equals(that.uri) && filePositions.equals(that.filePositions);
}

@Override
public int hashCode() {
return Objects.hash(uri, filePositions);
}
}

static class FeatureElementSelector implements DiscoverySelector {

private final Feature feature;
private final Node element;

private FeatureElementSelector(Feature feature) {
this(feature, feature);
}

private FeatureElementSelector(Feature feature, Node element) {
this.feature = requireNonNull(feature);
this.element = requireNonNull(element);
}

static FeatureElementSelector selectFeature(Feature feature) {
return new FeatureElementSelector(feature);
}

static FeatureElementSelector selectElement(Feature feature, Node element) {
return new FeatureElementSelector(feature, element);
}

static Optional<FeatureElementSelector> selectElementAt(Feature feature, FilePosition filePosition) {
return feature.findPathTo(candidate -> candidate.getLocation().getLine() == filePosition.getLine())
.map(nodes -> nodes.get(nodes.size() - 1))
.map(node -> new FeatureElementSelector(feature, node));
}

static Set<FeatureElementSelector> selectElementsOf(Feature feature, Node selected) {
if (selected instanceof Node.Container) {
Node.Container<?> container = (Node.Container<?>) selected;
return container.elements().stream()
.map(element -> new FeatureElementSelector(feature, element))
.collect(toSet());
}
return Collections.emptySet();
}

Feature getFeature() {
return feature;
}

Node getElement() {
return element;
}

@Override
public boolean equals(Object o) {
if (this == o)
return true;
if (o == null || getClass() != o.getClass())
return false;
FeatureElementSelector that = (FeatureElementSelector) o;
return feature.equals(that.feature) && element.equals(that.element);
}

@Override
public int hashCode() {
return Objects.hash(feature, element);
}
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package io.cucumber.junit.platform.engine;

import org.junit.platform.engine.TestDescriptor;
import org.junit.platform.engine.TestSource;
import org.junit.platform.engine.UniqueId;
import org.junit.platform.engine.support.descriptor.EngineDescriptor;
Expand Down Expand Up @@ -65,18 +64,4 @@ private CucumberEngineExecutionContext ifChildren(
return context;
}

void mergeFeature(FeatureDescriptor descriptor) {
recursivelyMerge(descriptor, this);
}

private static void recursivelyMerge(TestDescriptor descriptor, TestDescriptor parent) {
Optional<? extends TestDescriptor> byUniqueId = parent.findByUniqueId(descriptor.getUniqueId());
if (!byUniqueId.isPresent()) {
parent.addChild(descriptor);
} else {
byUniqueId.ifPresent(
existingParent -> descriptor.getChildren()
.forEach(child -> recursivelyMerge(child, existingParent)));
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
import io.cucumber.core.plugin.NoPublishFormatter;
import io.cucumber.core.plugin.PublishFormatter;
import io.cucumber.core.snippets.SnippetType;
import io.cucumber.junit.platform.engine.CucumberDiscoverySelectors.FeatureWithLinesSelector;
import io.cucumber.tagexpressions.Expression;
import io.cucumber.tagexpressions.TagExpressionParser;
import org.junit.platform.engine.ConfigurationParameters;
Expand All @@ -19,9 +20,9 @@
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

Expand All @@ -41,6 +42,7 @@
import static io.cucumber.junit.platform.engine.Constants.PLUGIN_PUBLISH_TOKEN_PROPERTY_NAME;
import static io.cucumber.junit.platform.engine.Constants.SNIPPET_TYPE_PROPERTY_NAME;
import static io.cucumber.junit.platform.engine.Constants.UUID_GENERATOR_PROPERTY_NAME;
import static java.util.Objects.requireNonNull;

class CucumberEngineOptions implements
io.cucumber.core.plugin.Options,
Expand All @@ -51,7 +53,7 @@ class CucumberEngineOptions implements
private final ConfigurationParameters configurationParameters;

CucumberEngineOptions(ConfigurationParameters configurationParameters) {
this.configurationParameters = configurationParameters;
this.configurationParameters = requireNonNull(configurationParameters);
}

@Override
Expand Down Expand Up @@ -177,14 +179,13 @@ NamingStrategy namingStrategy() {
.create(configurationParameters);
}

List<FeatureWithLines> featuresWithLines() {
Set<FeatureWithLinesSelector> featuresWithLines() {
return configurationParameters.get(FEATURES_PROPERTY_NAME,
s -> Arrays.stream(s.split(","))
.map(String::trim)
.map(FeatureWithLines::parse)
.sorted(Comparator.comparing(FeatureWithLines::uri))
.distinct()
.collect(Collectors.toList()))
.orElse(Collections.emptyList());
.map(FeatureWithLinesSelector::from)
.collect(Collectors.toSet()))
.orElse(Collections.emptySet());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,8 @@ public String getId() {
public TestDescriptor discover(EngineDiscoveryRequest discoveryRequest, UniqueId uniqueId) {
TestSource testSource = createEngineTestSource(discoveryRequest);
CucumberEngineDescriptor engineDescriptor = new CucumberEngineDescriptor(uniqueId, testSource);
new DiscoverySelectorResolver().resolveSelectors(discoveryRequest, engineDescriptor);
FeaturesPropertyResolver resolver = new FeaturesPropertyResolver(new DiscoverySelectorResolver());
resolver.resolveSelectors(discoveryRequest, engineDescriptor);
return engineDescriptor;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ public String name(Node node) {
}

@Override
public String nameExample(Node.Example node, Pickle pickle) {
public String nameExample(Node node, Pickle pickle) {
return exampleNameFunction.apply(node, pickle);
}
};
Expand Down
Loading