Skip to content

Commit

Permalink
Setup step delcarations for cucumber-java-lambda
Browse files Browse the repository at this point in the history
  • Loading branch information
mpkorstanje committed Jul 9, 2022
1 parent cbddfd0 commit 3cef4b6
Show file tree
Hide file tree
Showing 10 changed files with 765 additions and 1 deletion.
35 changes: 35 additions & 0 deletions java-lambda/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
Cucumber Java8
==============

Provides lambda based step definitions. To use add the `cucumber-java-lambda` dependency to your pom.xml:

```xml
<dependencies>
[...]
<dependency>
<groupId>io.cucumber</groupId>
<artifactId>cucumber-java-lambda</artifactId>
<version>${cucumber.version}</version>
<scope>test</scope>
</dependency>
[...]
</dependencies>
```

## Step Definitions

## Hooks

## Transformers

### Parameter Type

### Data Table Type

#### Default Transformers

#### Empty Cells

#### Transposing Tables

### DocString type
80 changes: 80 additions & 0 deletions java-lambda/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<parent>
<groupId>io.cucumber</groupId>
<artifactId>cucumber-jvm</artifactId>
<version>7.3.3-SNAPSHOT</version>
</parent>

<artifactId>cucumber-java-lambda</artifactId>
<packaging>jar</packaging>
<name>Cucumber-JVM: Java Lambda</name>

<properties>
<project.Automatic-Module-Name>io.cucumber.lambda</project.Automatic-Module-Name>
<apiguardian-api.version>1.1.2</apiguardian-api.version>
<junit-jupiter.version>5.8.2</junit-jupiter.version>
<typetools.version>0.6.3</typetools.version>
<assertj.version>3.22.0</assertj.version>
</properties>

<dependencyManagement>
<dependencies>
<dependency>
<groupId>io.cucumber</groupId>
<artifactId>cucumber-bom</artifactId>
<version>${project.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>org.junit</groupId>
<artifactId>junit-bom</artifactId>
<version>${junit-jupiter.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>

<dependencies>
<dependency>
<groupId>io.cucumber</groupId>
<artifactId>cucumber-core</artifactId>
</dependency>
<dependency>
<groupId>org.apiguardian</groupId>
<artifactId>apiguardian-api</artifactId>
<version>${apiguardian-api.version}</version>
</dependency>
<dependency>
<groupId>net.jodah</groupId>
<artifactId>typetools</artifactId>
<version>${typetools.version}</version>
</dependency>

<dependency>
<groupId>io.cucumber</groupId>
<artifactId>cucumber-junit-platform-engine</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.platform</groupId>
<artifactId>junit-platform-suite</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<scope>test</scope>
</dependency>

<dependency>
<groupId>org.assertj</groupId>
<artifactId>assertj-core</artifactId>
<version>${assertj.version}</version>
</dependency>
</dependencies>

</project>
30 changes: 30 additions & 0 deletions java-lambda/src/main/java/io/cucumber/lambda/Invoker.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package io.cucumber.lambda;

import io.cucumber.core.backend.CucumberBackendException;
import io.cucumber.core.backend.CucumberInvocationTargetException;
import io.cucumber.core.backend.Located;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

final class Invoker {

private Invoker() {

}

static Object invoke(Located located, Object target, Method method, Object... args) {
boolean accessible = method.canAccess(target);
try {
method.setAccessible(true);
return method.invoke(target, args);
} catch (IllegalArgumentException | IllegalAccessException e) {
throw new CucumberBackendException("Failed to invoke " + located.getLocation(), e);
} catch (InvocationTargetException e) {
throw new CucumberInvocationTargetException(located, e);
} finally {
method.setAccessible(accessible);
}
}

}
77 changes: 77 additions & 0 deletions java-lambda/src/main/java/io/cucumber/lambda/StepDeclaration.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
package io.cucumber.lambda;

import io.cucumber.core.backend.Located;
import io.cucumber.core.backend.SourceReference;

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;

import static io.cucumber.core.backend.SourceReference.fromStackTraceElement;
import static java.lang.String.format;
import static java.util.Objects.requireNonNull;

class StepDeclaration implements Located {
private final String expression;
private final Class<?> context;
private final StepDefinitionFunction function;
private final StackTraceElement location;
private SourceReference sourceReference;

StepDeclaration(String expression, Class<?> context, StepDefinitionFunction function, StackTraceElement location) {
this.expression = requireNonNull(expression, "expression should not be null");
this.context = requireNonNull(context, "context should not be null");
this.function = requireNonNull(function, "function should not be null");
this.location = requireNonNull(location, "location should not be null");

}

String getExpression() {
return expression;
}

Class<?> getContext() {
return context;
}

@Override
public final boolean isDefinedAt(StackTraceElement stackTraceElement) {
return location.getFileName() != null && location.getFileName().equals(stackTraceElement.getFileName());
}

@Override
public Optional<SourceReference> getSourceReference() {
if (sourceReference == null) {
sourceReference = fromStackTraceElement(location);
}
return Optional.of(sourceReference);
}

@Override
public final String getLocation() {
return location.toString();
}

void invoke(Object contextInstance, Object[] arguments) {
Method acceptMethod = getAcceptMethod(function.getClass());
Object body = Invoker.invoke(this, function, acceptMethod, contextInstance);
Method bodyAcceptMethod = getAcceptMethod(body.getClass());
Invoker.invoke(this, body, bodyAcceptMethod, arguments);
}

private Method getAcceptMethod(Class<?> bodyClass) {
List<Method> acceptMethods = new ArrayList<>();
for (Method method : bodyClass.getDeclaredMethods()) {
if (!method.isBridge() && !method.isSynthetic() && "accept".equals(method.getName())) {
acceptMethods.add(method);
}
}
if (acceptMethods.size() != 1) {
throw new IllegalStateException(format(
"Expected single 'accept' method on body class, found '%s'", acceptMethods));
}
return acceptMethods.get(0);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
package io.cucumber.lambda;

import org.apiguardian.api.API;

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

@API(status = EXPERIMENTAL, since = "7.4.0")
public interface StepDefinitionFunction {

@FunctionalInterface
interface C0A0 extends StepDefinitionFunction {
StepDefinitionBody.A0 accept();

}

@FunctionalInterface
interface C1A0<Context> extends StepDefinitionFunction {
StepDefinitionBody.A0 accept(Context context);

}

@FunctionalInterface
interface C1A1<Context, T1> extends StepDefinitionFunction {
StepDefinitionBody.A1<T1> accept(Context context);

}

@FunctionalInterface
interface C1A2<Context, T1, T2> extends StepDefinitionFunction {
StepDefinitionBody.A2<T1, T2> accept(Context context);

}

@FunctionalInterface
interface C1A3<Context, T1, T2, A3> extends StepDefinitionFunction {
StepDefinitionBody.A3<T1, T2, A3> accept(Context context);

}

@FunctionalInterface
interface C1A4<Context, T1, T2, T3, T4> extends StepDefinitionFunction {
StepDefinitionBody.A4<T1, T2, T3, T4> accept(Context context);

}

@FunctionalInterface
interface C1A5<Context, T1, T2, T3, T4, T5> extends StepDefinitionFunction {
StepDefinitionBody.A5<T1, T2, T3, T4, T5> accept(Context context);

}

@FunctionalInterface
interface C1A6<Context, T1, T2, T3, T4, T5, T6> extends StepDefinitionFunction {
StepDefinitionBody.A6<T1, T2, T3, T4, T5, T6> accept(Context context);

}

@FunctionalInterface
interface C1A7<Context, T1, T2, T3, T4, T5, T6, T7> extends StepDefinitionFunction {
StepDefinitionBody.A7<T1, T2, T3, T4, T5, T6, T7> accept(Context context);

}

@FunctionalInterface
interface C1A8<Context, T1, T2, T3, T4, T5, T6, T7, T8> extends StepDefinitionFunction {
StepDefinitionBody.A8<T1, T2, T3, T4, T5, T6, T7, T8> accept(Context context);

}

@FunctionalInterface
interface C1A9<Context, T1, T2, T3, T4, T5, T6, T7, T8, T9> extends StepDefinitionFunction {
StepDefinitionBody.A9<T1, T2, T3, T4, T5, T6, T7, T8, T9> accept(Context context);

}

interface StepDefinitionBody {

@FunctionalInterface
interface A0 extends StepDefinitionBody {
void accept() throws Throwable;

}

@FunctionalInterface
interface A1<T1> extends StepDefinitionBody {
void accept(T1 t1) throws Throwable;

}

@FunctionalInterface
interface A2<T1, T2> extends StepDefinitionBody {
void accept(T1 t1, T2 t2) throws Throwable;

}

@FunctionalInterface
interface A3<T1, T2, T3> extends StepDefinitionBody {
void accept(T1 t1, T2 t2, T3 t3) throws Throwable;

}

@FunctionalInterface
interface A4<T1, T2, T3, T4> extends StepDefinitionBody {
void accept(T1 t1, T2 t2, T3 t3, T4 t4) throws Throwable;

}

@FunctionalInterface
interface A5<T1, T2, T3, T4, T5> extends StepDefinitionBody {
void accept(T1 t1, T2 t2, T3 t3, T4 t4, T5 t5) throws Throwable;

}

@FunctionalInterface
interface A6<T1, T2, T3, T4, T5, T6> extends StepDefinitionBody {
void accept(T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6) throws Throwable;

}

@FunctionalInterface
interface A7<T1, T2, T3, T4, T5, T6, T7> extends StepDefinitionBody {
void accept(T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6, T7 t7) throws Throwable;

}

@FunctionalInterface
interface A8<T1, T2, T3, T4, T5, T6, T7, T8> extends StepDefinitionBody {
void accept(T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6, T7 t7, T8 t8) throws Throwable;

}

@FunctionalInterface
interface A9<T1, T2, T3, T4, T5, T6, T7, T8, T9> extends StepDefinitionBody {
void accept(T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6, T7 t7, T8 t8, T9 t9) throws Throwable;

}

}

}
Loading

0 comments on commit 3cef4b6

Please sign in to comment.