Skip to content

Core: TableConverter extracts child object values but not headers #1049

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

Closed
outadoc opened this issue Aug 23, 2016 · 6 comments
Closed

Core: TableConverter extracts child object values but not headers #1049

outadoc opened this issue Aug 23, 2016 · 6 comments

Comments

@outadoc
Copy link

outadoc commented Aug 23, 2016

Hi! I'd like to report a bug I encountered while trying out Cucumber on my freshly-converted Kotlin Android application. I'm not entirely sure if this is a bug with Cucumber or Kotlin, so I'll let you judge.

Steps to reproduce

  • Given TimeoLine.kt
data class TimeoLine (val id: String, val name: String, val direction: TimeoDirection, val networkCode: Int = 147, val color: String = "#34495E") {
    override fun toString(): String = name
}
  • Given TimeoDirection.kt
data class TimeoDirection (var id: String, var name: String) {
    override fun toString(): String = "$id - $name"
}

nb: As you can see, TimeoLine contains a TimeoDirection as a property named direction

  • Call DataTable.create() on a List<TimeoLine>

Expected behavior

The function returns a table that looks like this:

id name direction networkCode color
TRAM Tram A - Ifs Grace de Dieu 147 #ff3300
... ... ... ... ...

Observed behavior

cucumber.runtime.CucumberException: Table is unbalanced: expected 5 column(s) but found 6.
    at cucumber.api.DataTable.<init>(DataTable.java:63)
    at cucumber.runtime.table.TableConverter.createDataTable(TableConverter.java:272)
    at cucumber.runtime.table.TableConverter.toTable(TableConverter.java:258)
    at cucumber.api.DataTable.create(DataTable.java:45)
    at cucumber.api.DataTable.create(DataTable.java:31)
    at fr.outadev.android.transport.timeo.ParseStepDefinitions.iGetTheFollowingLines(ParseStepDefinitions.kt:65)
    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 cucumber.runtime.Utils$1.call(Utils.java:37)
    at cucumber.runtime.Timeout.timeout(Timeout.java:13)
    at cucumber.runtime.Utils.invoke(Utils.java:31)
    at cucumber.runtime.java.JavaStepDefinition.execute(JavaStepDefinition.java:38)
    at cucumber.runtime.StepDefinitionMatch.runStep(StepDefinitionMatch.java:37)
    at cucumber.runtime.Runtime.runStep(Runtime.java:299)
    [...]

By playing a bit with the DataTable conversion, you'll see ComplexTypeWriter extracts all the values in the object, including the members of TimeoDirection; but it only extracts the headers for the properties of the parent object (TimeoLine). It also causes some not-failing-but-extremely-confusing-behavior in diffs.

  • Runtime: java-8-openjdk
  • Lib version: info.cukes:cucumber-java:1.2.4
@mgurov
Copy link
Contributor

mgurov commented Aug 24, 2016

Could be related to #1042

@outadoc
Copy link
Author

outadoc commented Aug 24, 2016

I'm not sure how to compile the fix to test it, but it sure looks like that could be it.

@outadoc
Copy link
Author

outadoc commented Sep 9, 2016

If anyone seeing this knows of a workaround in the mean time, I'd be really interested!

@mpkorstanje
Copy link
Contributor

mpkorstanje commented Jun 16, 2017

There are two bugs in here. One being that that ComplexTypeWriter goes out of alignment when dealing with nested complex types. E.g. {a: "A", b: { bb: "BB"}, c: "C"} the other being that datatables were not designed to handle the nested complex types like b at all.

The first will be fixed with #1042.

The second will need some discussion.

I reckon the proper way would be to use the string representation of b. E.g:

{
  a: "A", 
  b: { 
    b1: "B1",
    b2: "B2",
    toString() {
       return this.b1 "-" + this.b2;
    }
  }, 
  c: "C"
}
| a | b     | c | 
| A | B1-B2 | C |

When dealing with lists, dates and other basic types we'd need to use the existing converters. E.g:

{
  a: "A", 
  b: ["B1", "B2"]
  c: "C"
}
| a | b      | c | 
| A | B1, B2 | C |

None of this seems to be supported by the current setup though. I'm that deeply into XStream. If anybody feels like figuring this out please do!

@mpkorstanje mpkorstanje changed the title Kotlin: TableConverter extracts child object values but not headers Core: TableConverter extracts child object values but not headers Jun 16, 2017
@mpkorstanje mpkorstanje added Core and removed Android labels Jun 16, 2017
@mpkorstanje
Copy link
Contributor

As it turns out I was mistaken. To achieve the desired result you have to add a converter that tells Cucumber how to present your object in a table. This should also prevent any table imbalances.

@XStreamConverter(TimeoDirectionConvertor::class)
data class TimeoDirection (var id: String, var name: String) {
    override fun toString(): String = "$id - $name"
}

class TimeoDirectionConvertor : SingleValueConverter {

    override fun toString(p0: Any?): String = p0.toString()

    override fun fromString(p0: String?): Any = {
        val (id, name) = p0!!.split(" - ");
        TimeoDirection(id, name)
    }

    override fun canConvert(p0: Class<*>?): Boolean = TimeoDirection::class.java.isAssignableFrom(p0)
}

@lock
Copy link

lock bot commented Oct 25, 2018

This thread has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs.

@lock lock bot locked as resolved and limited conversation to collaborators Oct 25, 2018
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants