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

Unable to configure a DataTableType for a List<List<String>> type #1884

Closed
Unequity opened this issue Feb 4, 2020 · 6 comments
Closed

Unable to configure a DataTableType for a List<List<String>> type #1884

Unequity opened this issue Feb 4, 2020 · 6 comments
Labels
⚡ enhancement Request for new functionality
Milestone

Comments

@Unequity
Copy link

Unequity commented Feb 4, 2020

Description
I've been unable to configure a DataTableType for the type List<List<String>>. When attempting to configure a @DataTableType(replaceWithEmptyString = "[none]") for a List of Lists of Strings, I get the following exception:

Tests run: 2, Failures: 0, Errors: 2, Skipped: 0, Time elapsed: 0.323 sec <<< FAILURE!
Test DataTableType to list of lists(Test DataTableType)  Time elapsed: 0.047 sec  <<< ERROR!
io.cucumber.datatable.DuplicateTypeException: There already is a data table type registered that can supply java.util.List<java.util.List<java.lang.String>>.
You are trying to register a TableTransformer for java.util.List<java.util.List<java.lang.String>>.
The existing data table type registered a TableCellTransformer for class java.lang.String.

at io.cucumber.datatable.DataTableTypeRegistry.defineDataTableType(DataTableTypeRegistry.java:72)
at io.cucumber.core.stepexpression.StepTypeRegistry.defineDataTableType(StepTypeRegistry.java:54)
at io.cucumber.core.runner.CachingGlue.lambda$prepareGlue$2(CachingGlue.java:187)
at java.util.ArrayList.forEach(ArrayList.java:1257)
at io.cucumber.core.runner.CachingGlue.prepareGlue(CachingGlue.java:187)
at io.cucumber.core.runner.Runner.runPickle(Runner.java:63)
at io.cucumber.junit.PickleRunners$NoStepDescriptions.run(PickleRunners.java:149)
at io.cucumber.junit.FeatureRunner.runChild(FeatureRunner.java:83)
at io.cucumber.junit.FeatureRunner.runChild(FeatureRunner.java:24)
at org.junit.runners.ParentRunner$4.run(ParentRunner.java:331)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:79)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:329)
at org.junit.runners.ParentRunner.access$100(ParentRunner.java:66)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:293)
at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)
at org.junit.runners.ParentRunner.run(ParentRunner.java:413)
at io.cucumber.junit.Cucumber.runChild(Cucumber.java:185)
at io.cucumber.junit.Cucumber.runChild(Cucumber.java:83)
at org.junit.runners.ParentRunner$4.run(ParentRunner.java:331)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:79)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:329)
at org.junit.runners.ParentRunner.access$100(ParentRunner.java:66)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:293)
at io.cucumber.junit.Cucumber$RunCucumber.evaluate(Cucumber.java:219)
at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)
at org.junit.runners.ParentRunner.run(ParentRunner.java:413)
at org.apache.maven.surefire.junit4.JUnit4Provider.execute(JUnit4Provider.java:252)
at org.apache.maven.surefire.junit4.JUnit4Provider.executeTestSet(JUnit4Provider.java:141)
at org.apache.maven.surefire.junit4.JUnit4Provider.invoke(JUnit4Provider.java:112)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.apache.maven.surefire.util.ReflectionUtils.invokeMethodWithArray(ReflectionUtils.java:189)
at org.apache.maven.surefire.booter.ProviderFactory$ProviderProxy.invoke(ProviderFactory.java:165)
at org.apache.maven.surefire.booter.ProviderFactory.invokeProvider(ProviderFactory.java:85)
at org.apache.maven.surefire.booter.ForkedBooter.runSuitesInProcess(ForkedBooter.java:115)
at org.apache.maven.surefire.booter.ForkedBooter.main(ForkedBooter.java:75)

This doesn't occur when attempting to configure a DataTableType for a List<String> or a List<Map<String, String>>

Context & Motivation
I'm currently upgrading a project that uses Cucumber 2 to Cucumber 5. The project has made heavy use of the Datatable asLists method, and many of the datatables have empty values, that were previously parsed as an empty string, but are now being parsed as null (due to the changes associated with this issue: #1617).

Because of the kind comparisons we are performing in the project, we want to be able to keep having empty strings returned from our datatables, and so I was looking to use (#1857) as a way to restore this, replacing the empty datatable cells in our feature files with [none] and configuring DataTableTypes for List<String>, List<Map<String, String>> and List<List<String>> which would all use replaceWithEmptyString with "[none]".

I'm not 100% confident that this is actually the correct approach to go about doing this, but nothing else I've tried so far seems to work for my use case, and the pattern appears to work fine for both the List<String> and List<Map<String, String>> types (as can be seen in the attached sample project), so it's unclear to me why this doesn't work for List<List<String>> If I'm doing this all wrong, it would be great to know what the best way to achieve the behaviour I want is!

To Reproduce
I've attached a minimal sample project that reproduces the issue when running the maven test target.
Alternatively you can reproduce this by setting up a DataTableType:

@DataTableType(replaceWithEmptyString = "[none]")
public List<List<String>> listOfStringListsType(DataTable dataTable) {
    return dataTable.asLists();
}

And then attempting to run a cucumber feature

My Environment

  • Cucumber version: 5.1.3
  • Build tool: Apache Maven 3.6.1
  • JDK 1.8.0_221

Sample project
cucumber-datatabletype-test.zip

@Unequity Unequity added the 🐛 bug Defect / Bug label Feb 4, 2020
@mpkorstanje
Copy link
Contributor

mpkorstanje commented Feb 4, 2020

The use case for data table transformers is transforming table to types other then List<Map<String, String>, Map<String,String>, List<List<String>> or List<String>. However I'm pleasantly surprised that you thought to use it this way, I had not considered it at all.

The problem you're running into is that registering a function DataTable -> List<List<String>>. This is the same as registering a function String -> String. The former transforms the entire data table, the later individual cells of a data table and is registered by default.

Looking at the implementation of the DataTableTypeRegistry one solution would be to make the predefined string and object data table types override-able.

For the primitives however we have double registrations. But I think it'd be okay not to make it possible to . Semantically speaking trying to parse white-space doesn't make much sense there.

@mpkorstanje
Copy link
Contributor

mpkorstanje commented Feb 4, 2020

So the use case to cover would be

Feature: Whitespace
  Scenario: Whitespace in a table
   Given a blank value
     | key | value   |
     | a   | [blank] | 
@Given("A blank value")
public void given_a_blank_value(Map<String, String> map){
    // map contains { "key":"a", "value": ""}
}

@DataTableType(replaceWithEmptyString = "[blank]")
public String listOfStringListsType(String cell) {
    return cell;
}

@Unequity
Copy link
Author

Unequity commented Feb 4, 2020

Yes, I think that make sense - so any step definition where the text in the cell is being parsed into a string (such as List<List<String>>, List<String>, and List<Map<String, String>) would be covered by that single DataTableType configuration in your example (were it possible to override the predefined String implementation for DataTableType)

mpkorstanje added a commit to cucumber/common that referenced this issue Feb 4, 2020
This enables the following in Cucumber-JVM:

```feature
Feature: Whitespace
  Scenario: Whitespace in a table
   Given a blank value
     | key | value   |
     | a   | [blank] |
```

```java
@given("A blank value")
public void given_a_blank_value(Map<String, String> map){
    // map contains { "a": ""}
}

@DataTableType(replaceWithEmptyString = "[blank]")
public String listOfStringListsType(String cell) {
    return cell;
}
```

Note that this only applies to `String` and `Object` the other build in types
can not be redefined. Though this could be considered if a clear usecase is
presented.

See: cucumber/cucumber-jvm#1884
mpkorstanje added a commit to cucumber/common that referenced this issue Feb 4, 2020
This enables the following in Cucumber-JVM:

```feature
Feature: Whitespace
  Scenario: Whitespace in a table
   Given a blank value
     | key | value   |
     | a   | [blank] |
```

```java
@given("A blank value")
public void given_a_blank_value(Map<String, String> map){
    // map contains { "key":"a", "value": ""}
}

@DataTableType(replaceWithEmptyString = "[blank]")
public String listOfStringListsType(String cell) {
    return cell;
}
```

Note that this only applies to `String` and `Object` the other build in types
can not be redefined. Though this could be considered if a clear usecase is
presented.

See: cucumber/cucumber-jvm#1884
@mpkorstanje
Copy link
Contributor

That is correct. You may find it interesting to read the data table libraries design documentation.

https://github.com/cucumber/cucumber/tree/master/datatable

@mpkorstanje
Copy link
Contributor

Can't promise any delivery dates but you are ofcourse free to interpret the current release frequency.

@Unequity
Copy link
Author

Unequity commented Feb 4, 2020

Fantastic! Thanks for all the help and the quick response too :)

@Unequity Unequity closed this as completed Feb 4, 2020
@mpkorstanje mpkorstanje reopened this Feb 4, 2020
@mpkorstanje mpkorstanje added ⚡ enhancement Request for new functionality and removed 🐛 bug Defect / Bug labels Feb 4, 2020
@mpkorstanje mpkorstanje added this to the 5.x.x milestone Feb 4, 2020
mpkorstanje added a commit to cucumber/common that referenced this issue Feb 5, 2020
…ed (#885)

This enables the following in Cucumber-JVM:

```feature
Feature: Whitespace
  Scenario: Whitespace in a table
   Given a blank value
     | key | value   |
     | a   | [blank] |
```

```java
@given("A blank value")
public void given_a_blank_value(Map<String, String> map){
    // map contains { "key":"a", "value": ""}
}

@DataTableType(replaceWithEmptyString = "[blank]")
public String listOfStringListsType(String cell) {
    return cell;
}
```

Note that this only applies to `String` and `Object` the other build in types
can not be redefined. Though this could be considered if a clear usecase is
presented.

See: cucumber/cucumber-jvm#1884
cukebot pushed a commit to cucumber-attic/datatable-java that referenced this issue Feb 6, 2020
…ed (#885)

This enables the following in Cucumber-JVM:

```feature
Feature: Whitespace
  Scenario: Whitespace in a table
   Given a blank value
     | key | value   |
     | a   | [blank] |
```

```java
@given("A blank value")
public void given_a_blank_value(Map<String, String> map){
    // map contains { "key":"a", "value": ""}
}

@DataTableType(replaceWithEmptyString = "[blank]")
public String listOfStringListsType(String cell) {
    return cell;
}
```

Note that this only applies to `String` and `Object` the other build in types
can not be redefined. Though this could be considered if a clear usecase is
presented.

See: cucumber/cucumber-jvm#1884
mpkorstanje added a commit that referenced this issue Sep 9, 2021
…ed (#885)

This enables the following in Cucumber-JVM:

```feature
Feature: Whitespace
  Scenario: Whitespace in a table
   Given a blank value
     | key | value   |
     | a   | [blank] |
```

```java
@given("A blank value")
public void given_a_blank_value(Map<String, String> map){
    // map contains { "key":"a", "value": ""}
}

@DataTableType(replaceWithEmptyString = "[blank]")
public String listOfStringListsType(String cell) {
    return cell;
}
```

Note that this only applies to `String` and `Object` the other build in types
can not be redefined. Though this could be considered if a clear usecase is
presented.

See: #1884
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
⚡ enhancement Request for new functionality
Projects
None yet
Development

No branches or pull requests

2 participants