Skip to content
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package io.cucumber.core.options;

import io.cucumber.core.snippets.SnippetType;
import io.cucumber.core.backend.ObjectFactory;
import io.cucumber.core.exception.CucumberException;
import io.cucumber.core.io.MultiLoader;
import io.cucumber.core.io.ResourceLoader;
Expand Down Expand Up @@ -50,6 +51,7 @@ public RuntimeOptionsBuilder parse(Class<?> clazz) {
addSnippets(options, args);
addGlue(options, args);
addFeatures(options, args);
addObjectFactory(options, args);
}
}
addDefaultFeaturePathIfNoFeaturePathIsSpecified(args, clazz);
Expand Down Expand Up @@ -146,13 +148,18 @@ private void addDefaultGlueIfNoOverridingGlueIsSpecified(RuntimeOptionsBuilder a
}
}


private void addStrict(CucumberOptions options, RuntimeOptionsBuilder args) {
if (options.strict()) {
args.setStrict(true);
}
}

private void addObjectFactory(CucumberOptions options, RuntimeOptionsBuilder args) {
if (options.objectFactory() != null) {
args.setObjectFactoryClass(options.objectFactory());
}
}

private static String packagePath(Class clazz) {
String packageName = packageName(clazz);

Expand Down Expand Up @@ -204,5 +211,7 @@ public interface CucumberOptions {
String[] name();

SnippetType snippets();

Class<? extends ObjectFactory> objectFactory();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -121,4 +121,4 @@ public String get(Object key) {
}

}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -38,15 +38,15 @@ public RuntimeOptionsBuilder parse(Map<String, String> properties) {

String cucumberObjectFactory = properties.get(CUCUMBER_OBJECT_FACTORY_PROPERTY_NAME);
if (cucumberObjectFactory != null) {
Class<? extends ObjectFactory> objectFactoryClass = parse(cucumberObjectFactory);
Class<? extends ObjectFactory> objectFactoryClass = parseObjectFactory(cucumberObjectFactory);
builder.setObjectFactoryClass(objectFactoryClass);
}

return builder;
}

@SuppressWarnings("unchecked")
private Class<? extends ObjectFactory> parse(String cucumberObjectFactory) {
static Class<? extends ObjectFactory> parseObjectFactory(String cucumberObjectFactory) {
Class<?> objectFactoryClass;
try {
objectFactoryClass = Class.forName(cucumberObjectFactory);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,9 @@ RuntimeOptionsBuilder parse(List<String> args) {
throw new CucumberException("--count must be > 0");
}
parsedOptions.setCount(count);
} else if (arg.equals("--object-factory")) {
String objectFactoryClassName = args.remove(0);
parsedOptions.setObjectFactoryClass(CucumberPropertiesParser.parseObjectFactory(objectFactoryClassName));
} else if (arg.startsWith("-")) {
printUsage();
throw new CucumberException("Unknown option: " + arg);
Expand Down
3 changes: 0 additions & 3 deletions core/src/main/java/io/cucumber/core/snippets/SnippetType.java
Original file line number Diff line number Diff line change
@@ -1,8 +1,5 @@
package io.cucumber.core.snippets;

import org.apiguardian.api.API;

@API(status = API.Status.STABLE)
public enum SnippetType {
UNDERSCORE(new UnderscoreJoiner()),
CAMELCASE(new CamelCaseJoiner());
Expand Down
8 changes: 7 additions & 1 deletion core/src/main/resources/io/cucumber/core/options/USAGE.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
Usage: java cucumber.api.cli.Main [options] [ [DIR|DIR URI] | [ [FILE|FILE URI][:LINE]* ] | @[FILE|FILE URI] ]+
Usage: java io.cucumber.core.cli.Main [options] [ [DIR|DIR URI] | [ [FILE|FILE URI][:LINE]* ] | @[FILE|FILE URI] ]+

Options:

Expand Down Expand Up @@ -50,6 +50,12 @@ Options:
--count Number of scenarios to be executed. If not
specified all scenarios are run.

--object-factory CLASSNAME Uses the class specified by CLASSNAME as
object factory. Be aware that the class is
loaded through a service loader and therefore
also needs to be specified in:
META-INF/services/io.cucumber.core.backend.ObjectFactory

Feature path examples:

<path> Load the files with the extension ".feature"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,13 @@
*/
SnippetType snippets() default SnippetType.UNDERSCORE;

/**
* A custom ObjectFactory.
*
* @return The class of the custim ObjectFactory to use.
*/
Class<? extends io.cucumber.core.backend.ObjectFactory> objectFactory() default NoObjectFactory.class;

/**
* Pass options to the JUnit runner.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import io.cucumber.core.plugin.Plugin;
import io.cucumber.core.snippets.SnippetType;
import io.cucumber.core.backend.ObjectFactory;
import io.cucumber.core.exception.CucumberException;
import io.cucumber.core.plugin.PluginFactory;
import io.cucumber.core.plugin.Plugins;
Expand All @@ -19,6 +20,7 @@
import static org.hamcrest.collection.IsIterableContainingInOrder.contains;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;

Expand Down Expand Up @@ -48,6 +50,7 @@ public void create_without_options() {
.addDefaultFormatterIfNotPresent()
.build();
assertFalse(runtimeOptions.isStrict());
assertNull(runtimeOptions.getObjectFactoryClass());
assertThat(runtimeOptions.getFeaturePaths(), contains(uri("classpath:io/cucumber/core/options")));
assertThat(runtimeOptions.getGlue(), contains(uri("classpath:io/cucumber/core/options")));
Plugins plugins = new Plugins(new PluginFactory(), runtimeOptions);
Expand Down Expand Up @@ -100,6 +103,12 @@ public void create_with_multiple_names() {
assertEquals("name2", getRegexpPattern(iterator.next()));
}

@Test
public void testObjectFactory() {
RuntimeOptions runtimeOptions = parser().parse(ClassWithCustomObjectFactory.class).build();
assertEquals(TestObjectFactory.class, runtimeOptions.getObjectFactoryClass());
}

@Test
public void create_with_snippets() {
RuntimeOptions runtimeOptions = parser().parse(Snippets.class).build();
Expand Down Expand Up @@ -238,6 +247,11 @@ private static class BaseClassWithMonoChromeFalse {
// empty
}

@CucumberOptions(objectFactory = TestObjectFactory.class)
private static class ClassWithCustomObjectFactory {
// empty
}

@CucumberOptions(plugin = "io.cucumber.core.plugin.AnyStepDefinitionReporter")
private static class ClassWithNoFormatterPlugin {
// empty
Expand Down Expand Up @@ -336,6 +350,10 @@ public SnippetType snippets() {
return annotation.snippets();
}

@Override
public Class<? extends ObjectFactory> objectFactory() {
return (annotation.objectFactory() == NoObjectFactory.class) ? null : annotation.objectFactory();
}
}

private static class CoreCucumberOptionsProvider implements CucumberOptionsAnnotationParser.OptionsProvider {
Expand All @@ -348,4 +366,24 @@ public CucumberOptionsAnnotationParser.CucumberOptions getOptions(Class<?> clazz
return new CoreCucumberOptions(annotation);
}
}

private static final class TestObjectFactory implements ObjectFactory {

@Override
public boolean addClass(Class<?> glueClass) {
return false;
}

@Override
public <T> T getInstance(Class<T> glueClass) {
return null;
}

@Override
public void start() {}

@Override
public void stop() {}

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,16 +23,15 @@ public void should_parse_cucumber_options(){
assertThat(options.getGlue(), equalTo(singletonList(URI.create("classpath:com/example"))));
}


@Test
public void should_parse_cucumber_object_factory(){
properties.put(Constants.CUCUMBER_OBJECT_FACTORY_PROPERTY_NAME, CustomObjectFactory.class.getName());
RuntimeOptions options = cucumberPropertiesParser.parse(properties).build();
assertThat(options.getObjectFactoryClass(), equalTo(CustomObjectFactory.class));
}

private static final class CustomObjectFactory implements ObjectFactory {

private static final class CustomObjectFactory implements ObjectFactory {
@Override
public boolean addClass(Class<?> glueClass) {
return false;
Expand All @@ -53,5 +52,4 @@ public void stop() {

}
}

}
}
30 changes: 30 additions & 0 deletions core/src/test/java/io/cucumber/core/options/NoObjectFactory.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package io.cucumber.core.options;

import io.cucumber.core.backend.ObjectFactory;

/**
* This object factory does nothing. It is solely needed for marking purposes.
*/
final class NoObjectFactory implements ObjectFactory {

private NoObjectFactory() {
// No need for instantiation
}

@Override
public boolean addClass(Class<?> glueClass) {
return false;
}

@Override
public <T> T getInstance(Class<T> glueClass) {
return null;
}

@Override
public void start() {}

@Override
public void stop() {}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
package io.cucumber.core.options;

import static org.junit.jupiter.api.Assertions.*;

import java.util.Arrays;

import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;

import io.cucumber.core.backend.ObjectFactory;
import io.cucumber.core.feature.RerunLoader;
import io.cucumber.core.io.MultiLoader;

final class RuntimeOptionsParserTest {

private RuntimeOptionsParser parser;

@BeforeEach
void setUp() throws Exception {
this.parser = new RuntimeOptionsParser(new RerunLoader( new MultiLoader(this.getClass().getClassLoader())));
}

@Test
void testParseWithObjectFactoryArgument() {
RuntimeOptionsBuilder optionsBuilder = this.parser.parse(Arrays.asList("--object-factory", TestObjectFactory.class.getName()));
assertNotNull(optionsBuilder);
RuntimeOptions options = optionsBuilder.build();
assertNotNull(options);
assertEquals(TestObjectFactory.class, options.getObjectFactoryClass());
}


private static final class TestObjectFactory implements ObjectFactory {

@Override
public boolean addClass(Class<?> glueClass) {
return false;
}

@Override
public <T> T getInstance(Class<T> glueClass) {
return null;
}

@Override
public void start() {}

@Override
public void stop() {}

}
}
10 changes: 10 additions & 0 deletions junit/src/main/java/io/cucumber/junit/CucumberOptions.java
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,16 @@
*/
boolean stepNotifications() default false;

/**
* Specify a custom ObjectFactory.
* <p>
* In case a custom ObjectFactory is needed, the class can be specified here.
* A custom ObjectFactory might be needed when more granular control is needed
* over the dependency injection mechanism.
*/
Class<? extends io.cucumber.core.backend.ObjectFactory> objectFactory() default NoObjectFactory.class;


enum SnippetType {
UNDERSCORE, CAMELCASE
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package io.cucumber.junit;

import io.cucumber.core.snippets.SnippetType;
import io.cucumber.core.backend.ObjectFactory;
import io.cucumber.core.options.CucumberOptionsAnnotationParser;

final class JUnitCucumberOptionsProvider implements CucumberOptionsAnnotationParser.OptionsProvider {
Expand Down Expand Up @@ -68,13 +69,18 @@ public String[] name() {
@Override
public SnippetType snippets() {
switch (annotation.snippets()) {
case UNDERSCORE:
return SnippetType.UNDERSCORE;
case CAMELCASE:
return SnippetType.CAMELCASE;
default:
throw new IllegalArgumentException("" + annotation.snippets());
case UNDERSCORE:
return SnippetType.UNDERSCORE;
case CAMELCASE:
return SnippetType.CAMELCASE;
default:
throw new IllegalArgumentException("" + annotation.snippets());
}
}

@Override
public Class<? extends ObjectFactory> objectFactory() {
return (annotation.objectFactory() == NoObjectFactory.class) ? null : annotation.objectFactory();
}
}
}
30 changes: 30 additions & 0 deletions junit/src/main/java/io/cucumber/junit/NoObjectFactory.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package io.cucumber.junit;

import io.cucumber.core.backend.ObjectFactory;

/**
* This object factory does nothing. It is solely needed for marking purposes.
*/
final class NoObjectFactory implements ObjectFactory {

private NoObjectFactory() {
// No need for instantiation
}

@Override
public boolean addClass(Class<?> glueClass) {
return false;
}

@Override
public <T> T getInstance(Class<T> glueClass) {
return null;
}

@Override
public void start() {}

@Override
public void stop() {}

}
Loading