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

Empty DataTable with Enum not converted to empty list #1701

Closed
karoisuzvards opened this issue Jul 17, 2019 · 1 comment
Closed

Empty DataTable with Enum not converted to empty list #1701

karoisuzvards opened this issue Jul 17, 2019 · 1 comment

Comments

@karoisuzvards
Copy link

karoisuzvards commented Jul 17, 2019

Summary

In order to use empty Datatable with enum types -> in cucumber 2.x Datatable was converted to empty List but now exception happens in cucumber 4.x

Current Behavior

Exception happens, workarounds available. Would it be possible to avoid these workarounds but just receive emptyList like in old cucumber 2.x days ?

Steps to Reproduce

Feature:

Scenario I love empty enum datatables

Given I have enabled config with enums here
| YES |
| NO  |
| NA  |
When I have enabled config with enums here
| |
Then error happens

TrileanStepDefs:

@When("^I have enabled config with enums here:$")
    public void enableDisambiguity(List<Trilean> trileans) {
        foo(trileans);
    }

TypeRegistryConfigurer:

public class ParameterTypes implements TypeRegistryConfigurer {

    @Override
    public Locale locale() {
        return ENGLISH;
    }

    @Override
    public void configureTypeRegistry(TypeRegistry typeRegistry) {
        Transformer transformer = new Transformer();
        typeRegistry.setDefaultDataTableCellTransformer(transformer);
        typeRegistry.setDefaultDataTableEntryTransformer(transformer);
        typeRegistry.setDefaultParameterTransformer(transformer);
        typeRegistry.defineDataTableType(trileanType());
    }

    private DataTableType trileanType() {
        return new DataTableType(Trilean.class, 
                    (TableCellTransformer<Trilean>) Trilean::valueOf);
    }

Trilean.java

public enum Trilean
{
    YES, NO, NA
}

Stacktrace:

cucumber.runtime.CucumberException: Could not convert arguments for step [^I have enabled config with enums here:$] defined at 'com.magic.TrileanStepDefs.enableDisambiguity(Trilean>) in file:/path/to/app/build/classes/java/main/'.
The details are in the stacktrace below.
        at cucumber.runner.PickleStepDefinitionMatch.couldNotConvertArguments(PickleStepDefinitionMatch.java:69)
        at cucumber.runner.PickleStepDefinitionMatch.runStep(PickleStepDefinitionMatch.java:46)
        at cucumber.runner.TestStep.executeStep(TestStep.java:65)
        at cucumber.runner.TestStep.run(TestStep.java:50)
        at cucumber.runner.PickleStepTestStep.run(PickleStepTestStep.java:43)
        at cucumber.runner.TestCase.run(TestCase.java:46)
        at cucumber.runner.Runner.runPickle(Runner.java:50)
        at cucumber.runtime.Runtime$1.run(Runtime.java:104)
        at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
        at java.util.concurrent.FutureTask.run(FutureTask.java:266)
        at cucumber.runtime.Runtime$SameThreadExecutorService.execute(Runtime.java:258)
        at java.util.concurrent.AbstractExecutorService.submit(AbstractExecutorService.java:112)
        at cucumber.runtime.Runtime.run(Runtime.java:101)
        at io.cucumber.core.cli.Main.run(Main.java:43)
        at io.cucumber.core.cli.Main.main(Main.java:14)
Caused by: io.cucumber.datatable.CucumberDataTableException: 'java.util.List<java.util.List<com.magic.Trilean>>' could not transform
      |  |

        at io.cucumber.datatable.DataTableType.transform(DataTableType.java:162)
        at io.cucumber.datatable.DataTableTypeRegistryTableConverter.toListOrNull(DataTableTypeRegistryTableConverter.java:150)
        at io.cucumber.datatable.DataTableTypeRegistryTableConverter.toListOrNull(DataTableTypeRegistryTableConverter.java:138)
        at io.cucumber.datatable.DataTableTypeRegistryTableConverter.toList(DataTableTypeRegistryTableConverter.java:125)
        at io.cucumber.datatable.DataTableTypeRegistryTableConverter.convert(DataTableTypeRegistryTableConverter.java:96)
        at io.cucumber.datatable.DataTable.convert(DataTable.java:362)
        at io.cucumber.stepexpression.StepExpressionFactory$3.transform(StepExpressionFactory.java:73)
        at io.cucumber.stepexpression.DataTableArgument.getValue(DataTableArgument.java:19)
        at cucumber.runner.PickleStepDefinitionMatch.runStep(PickleStepDefinitionMatch.java:41)
        ... 13 more
Caused by: java.lang.IllegalArgumentException: No enum constant com.magic.Trilean.
        at java.lang.Enum.valueOf(Enum.java:238)
        at com.magic.Trilean.valueOf(Trilean.java:3)
        at io.cucumber.datatable.DataTableType$TableCellTransformerAdaptor.transform(DataTableType.java:222)
        at io.cucumber.datatable.DataTableType$TableCellTransformerAdaptor.transform(DataTableType.java:203)
        at io.cucumber.datatable.DataTableType.transform(DataTableType.java:159)
        ... 21 more

Context & Motivation

Allows to migrate my old test suite easier or suggesting to ease migration pain for other users

Possible Solution

Current workaround is to create a new stepdef which will call same method with empty list

@When("^I disable config$")
    public void disableDisambiguity() {
        foo(Collections.emptyList());
    }

Another approach is to workaround by wrapping around enum: (http://grasshopper.tech/340/ section DataTable TO a Single object)

public class Trileans {
    private List<Trilean> trileans;
    
    public Trileans(List<Trilean> trileans){
          this.trileans = trileans;
     }
}

Given I have enums
  |  |

@Given("I have enums")
public void IHaveEnums(Trileans trileans) {}

registry.defineDataTableType(new DataTableType(Trileans.class, new TableTransformer<Trileans>() {
    @Override
    public Trileans transform(DataTable table) throws Throwable {
        List<Trilean> trills = table.asList()
                                            .stream()
                                            .map(m -> Trilean::valueOf )
                                            .collect(Collectors.toList());
        return new Trileans(trills);
    }
}));

Would it be possible to use TableTransformer to achieve this ? Tried something like this but did not succeed!

   private DataTableType trilean() {
        return new DataTableType(List.class, (TableTransformer<List>) table -> table.asList()
            .stream()
            .map(Trilean::valueOf)
            .collect(Collectors.toList()));

Your Environment

  • Version used: cucumber-jvm 4.6.0
  • Operating System and version: Mac OS 10.14.5
@mpkorstanje
Copy link
Contributor

mpkorstanje commented Jul 18, 2019

In order to use empty Datatable with enum types -> in cucumber 2.x Datatable was converted to empty List but now exception happens in cucumber 4.x

This behavior will not be restored. It was facilitated by XStream, and the way XStream was used in Cucumber was quite magical, completely undocumented and also rather unpredictable. It is unfortunate that you've found this behavior to be be useful.

For consistency (and after #1617) the following transformations should hold:

| a | 
| b |  => [a, b, c]
| c | 
| a | 
|   |  => [a, null, c]
| b | 
| a | 
|   |  => [a, null]
|   |  => [null]
      => []

So

|   |  => []

Would be quite inconsistent. Or in other words the number of rows/items in the list should remain invariant.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants