package cucumber.runtime.table; import cucumber.api.DataTable; import cucumber.api.Format; import cucumber.api.Transformer; import cucumber.api.Transpose; import cucumber.deps.com.thoughtworks.xstream.annotations.XStreamConverter; import cucumber.deps.com.thoughtworks.xstream.converters.javabean.JavaBeanConverter; import cucumber.runtime.StepDefinition; import cucumber.runtime.StepDefinitionMatch; import cucumber.runtime.StubStepDefinition; import cucumber.runtime.xstream.LocalizedXStreams; import gherkin.I18n; import gherkin.formatter.Argument; import gherkin.formatter.model.Comment; import gherkin.formatter.model.DataTableRow; import gherkin.formatter.model.Step; import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.Calendar; import java.util.Date; import java.util.List; import java.util.Map; import static java.util.Arrays.asList; import static java.util.Collections.emptyList; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNull; public class FromDataTableTest { @Rule public ExpectedException thrown = ExpectedException.none(); private static final List<Argument> NO_ARGS = emptyList(); private static final List<Comment> NO_COMMENTS = emptyList(); public static class StepDefs { public List<PrimitiveContainer> listOfPrimitiveContainers; public List<UserPojo> listOfPojos; public List<UserBean> listOfBeans; public List<UserWithNameField> listOfUsersWithNameField; public List<List<Double>> listOfListOfDoubles; public List<Map<String, Date>> listOfMapsOfStringToDate; public List<Map<String, Object>> listOfMapsOfStringToObject; public Map<Double, Double> mapOfDoubleToDouble; public DataTable dataTable; public void listOfPrimitiveContainers(List<PrimitiveContainer> primitiveContainers) { this.listOfPrimitiveContainers = primitiveContainers; } public void listOfPojos(@Format("yyyy-MM-dd") List<UserPojo> listOfPojos) { this.listOfPojos = listOfPojos; } public void listOfPojosTransposed(@Transpose @Format("yyyy-MM-dd") List<UserPojo> listOfPojos) { this.listOfPojos = listOfPojos; } public void listOfBeans(@Format("yyyy-MM-dd") List<UserBean> listOfBeans) { this.listOfBeans = listOfBeans; } public void listOfBeansTransposed(@Transpose @Format("yyyy-MM-dd") List<UserBean> listOfBeans) { this.listOfBeans = listOfBeans; } public void listOfUsersWithNameField(@Format("yyyy-MM-dd") List<UserWithNameField> listOfUsersWithNameField) { this.listOfUsersWithNameField = listOfUsersWithNameField; } public void listOfUsersTransposedWithNameField(@Transpose @Format("yyyy-MM-dd") List<UserWithNameField> listOfUsersWithNameField) { this.listOfUsersWithNameField = listOfUsersWithNameField; } public void listOfListOfDoubles(List<List<Double>> listOfListOfDoubles) { this.listOfListOfDoubles = listOfListOfDoubles; } public void listOfListOfDoublesTransposed(@Transpose List<List<Double>> listOfListOfDoubles) { this.listOfListOfDoubles = listOfListOfDoubles; } public void listOfMapsOfStringToDate(@Format("yyyy-MM-dd") List<Map<String, Date>> listOfMapsOfStringToDate) { this.listOfMapsOfStringToDate = listOfMapsOfStringToDate; } public void listOfMapsOfStringToObject(List<Map<String, Object>> listOfMapsOfStringToObject) { this.listOfMapsOfStringToObject = listOfMapsOfStringToObject; } public void plainDataTable(DataTable dataTable) { this.dataTable = dataTable; } public void listOfMapsOfDateToString(List<Map<Date, String>> mapsOfDateToString) { } public void listOfMaps(List<Map> maps) { } public void mapOfDoubleToDouble(Map<Double,Double> mapOfDoubleToDouble) { this.mapOfDoubleToDouble = mapOfDoubleToDouble; } } @Test public void transforms_to_list_of_pojos() throws Throwable { Method m = StepDefs.class.getMethod("listOfPojos", List.class); StepDefs stepDefs = runStepDef(m, listOfDatesAndCalWithHeader()); assertEquals(sidsBirthday(), stepDefs.listOfPojos.get(0).birthDate); assertEquals(sidsDeathcal().getTime(), stepDefs.listOfPojos.get(0).deathCal.getTime()); assertNull(stepDefs.listOfPojos.get(1).deathCal); } @Test public void transforms_to_list_of_pojos_transposed() throws Throwable { Method m = StepDefs.class.getMethod("listOfPojosTransposed", List.class); StepDefs stepDefs = runStepDef(m, transposedListOfDatesAndCalWithHeader()); assertEquals(sidsBirthday(), stepDefs.listOfPojos.get(0).birthDate); assertEquals(sidsDeathcal().getTime(), stepDefs.listOfPojos.get(0).deathCal.getTime()); assertNull(stepDefs.listOfPojos.get(1).deathCal); } @Test public void assigns_null_to_objects_when_empty_except_boolean_special_case() throws Throwable { Method m = StepDefs.class.getMethod("listOfPrimitiveContainers", List.class); List<DataTableRow> rows = new ArrayList<DataTableRow>(); rows.add(new DataTableRow(NO_COMMENTS, asList("number", "bool", "bool2"), 1)); rows.add(new DataTableRow(NO_COMMENTS, asList("1", "false", "true"), 2)); rows.add(new DataTableRow(NO_COMMENTS, asList("", "", ""), 3)); StepDefs stepDefs = runStepDef(m, rows); assertEquals(new Integer(1), stepDefs.listOfPrimitiveContainers.get(0).number); assertEquals(new Boolean(false), stepDefs.listOfPrimitiveContainers.get(0).bool); assertEquals(true, stepDefs.listOfPrimitiveContainers.get(0).bool2); assertEquals(null, stepDefs.listOfPrimitiveContainers.get(1).number); assertEquals(new Boolean(false), stepDefs.listOfPrimitiveContainers.get(1).bool); assertEquals(false, stepDefs.listOfPrimitiveContainers.get(1).bool2); } @Test public void transforms_to_list_of_beans() throws Throwable { Method m = StepDefs.class.getMethod("listOfBeans", List.class); StepDefs stepDefs = runStepDef(m, listOfDatesWithHeader()); assertEquals(sidsBirthday(), stepDefs.listOfBeans.get(0).getBirthDate()); } @Test public void transforms_to_list_of_beans_transposed() throws Throwable { Method m = StepDefs.class.getMethod("listOfBeansTransposed", List.class); StepDefs stepDefs = runStepDef(m, transposedListOfDatesWithHeader()); assertEquals(sidsBirthday(), stepDefs.listOfBeans.get(0).getBirthDate()); } @Test public void converts_table_to_list_of_class_with_special_fields() throws Throwable { Method m = StepDefs.class.getMethod("listOfUsersWithNameField", List.class); StepDefs stepDefs = runStepDef(m, listOfDatesAndNamesWithHeader()); assertEquals(sidsBirthday(), stepDefs.listOfUsersWithNameField.get(0).birthDate); assertEquals("Sid", stepDefs.listOfUsersWithNameField.get(0).name.first); assertEquals("Vicious", stepDefs.listOfUsersWithNameField.get(0).name.last); } @Test public void converts_table_to_list_of_class_with_special_fields_transposed() throws Throwable { Method m = StepDefs.class.getMethod("listOfUsersTransposedWithNameField", List.class); StepDefs stepDefs = runStepDef(m, transposedListOfDatesAndNamesWithHeader()); assertEquals(sidsBirthday(), stepDefs.listOfUsersWithNameField.get(0).birthDate); assertEquals("Sid", stepDefs.listOfUsersWithNameField.get(0).name.first); assertEquals("Vicious", stepDefs.listOfUsersWithNameField.get(0).name.last); } @Test public void transforms_to_map_of_double_to_double() throws Throwable { Method m = StepDefs.class.getMethod("mapOfDoubleToDouble", Map.class); StepDefs stepDefs = runStepDef(m, listOfDoublesWithoutHeader()); assertEquals(Double.valueOf(999.0), stepDefs.mapOfDoubleToDouble.get(1000.0)); assertEquals(Double.valueOf(-0.5), stepDefs.mapOfDoubleToDouble.get(0.5)); assertEquals(Double.valueOf(99.5), stepDefs.mapOfDoubleToDouble.get(100.5)); } @Test public void transforms_to_list_of_single_values() throws Throwable { Method m = StepDefs.class.getMethod("listOfListOfDoubles", List.class); StepDefs stepDefs = runStepDef(m, listOfDoublesWithoutHeader()); assertEquals("[[100.5, 99.5], [0.5, -0.5], [1000.0, 999.0]]", stepDefs.listOfListOfDoubles.toString()); } @Test public void transforms_to_list_of_single_values_transposed() throws Throwable { Method m = StepDefs.class.getMethod("listOfListOfDoublesTransposed", List.class); StepDefs stepDefs = runStepDef(m, transposedListOfDoublesWithoutHeader()); assertEquals("[[100.5, 99.5], [0.5, -0.5], [1000.0, 999.0]]", stepDefs.listOfListOfDoubles.toString()); } @Test public void transforms_to_list_of_map_of_string_to_date() throws Throwable { Method m = StepDefs.class.getMethod("listOfMapsOfStringToDate", List.class); StepDefs stepDefs = runStepDef(m, listOfDatesWithHeader()); assertEquals(sidsBirthday(), stepDefs.listOfMapsOfStringToDate.get(0).get("Birth Date")); } @Test public void transforms_to_list_of_map_of_string_to_object() throws Throwable { Method m = StepDefs.class.getMethod("listOfMapsOfStringToObject", List.class); StepDefs stepDefs = runStepDef(m, listOfDatesWithHeader()); assertEquals("1957-05-10", stepDefs.listOfMapsOfStringToObject.get(0).get("Birth Date")); } @Test public void passes_plain_data_table() throws Throwable { Method m = StepDefs.class.getMethod("plainDataTable", DataTable.class); StepDefs stepDefs = runStepDef(m, listOfDatesWithHeader()); assertEquals("1957-05-10", stepDefs.dataTable.raw().get(1).get(0)); assertEquals("Birth Date", stepDefs.dataTable.raw().get(0).get(0)); } private StepDefs runStepDef(Method method, List<DataTableRow> rows) throws Throwable { StepDefs stepDefs = new StepDefs(); StepDefinition stepDefinition = new StubStepDefinition(stepDefs, method, "some pattern"); Step stepWithRows = new Step(NO_COMMENTS, "Given ", "something", 10, rows, null); ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); StepDefinitionMatch stepDefinitionMatch = new StepDefinitionMatch(NO_ARGS, stepDefinition, "some.feature", stepWithRows, new LocalizedXStreams(classLoader)); stepDefinitionMatch.runStep(new I18n("en")); return stepDefs; } private List<DataTableRow> listOfDatesWithHeader() { List<DataTableRow> rows = new ArrayList<DataTableRow>(); rows.add(new DataTableRow(NO_COMMENTS, asList("Birth Date"), 1)); rows.add(new DataTableRow(NO_COMMENTS, asList("1957-05-10"), 2)); return rows; } private List<DataTableRow> listOfDatesAndCalWithHeader() { List<DataTableRow> rows = new ArrayList<DataTableRow>(); rows.add(new DataTableRow(NO_COMMENTS, asList("Birth Date", "Death Cal"), 1)); rows.add(new DataTableRow(NO_COMMENTS, asList("1957-05-10", "1979-02-02"), 2)); rows.add(new DataTableRow(NO_COMMENTS, asList("", ""), 3)); return rows; } private List<DataTableRow> listOfDatesAndNamesWithHeader() { List<DataTableRow> rows = new ArrayList<DataTableRow>(); rows.add(new DataTableRow(NO_COMMENTS, asList("Birth Date", "Name"), 1)); rows.add(new DataTableRow(NO_COMMENTS, asList("1957-05-10", "Sid Vicious"), 2)); return rows; } private List<DataTableRow> listOfDoublesWithoutHeader() { List<DataTableRow> rows = new ArrayList<DataTableRow>(); rows.add(new DataTableRow(NO_COMMENTS, asList("100.5", "99.5"), 2)); rows.add(new DataTableRow(NO_COMMENTS, asList("0.5", "-0.5"), 2)); rows.add(new DataTableRow(NO_COMMENTS, asList("1000", "999"), 2)); return rows; } private List<DataTableRow> transposedListOfDatesWithHeader() { List<DataTableRow> rows = new ArrayList<DataTableRow>(); rows.add(new DataTableRow(NO_COMMENTS, asList("Birth Date", "1957-05-10"), 1)); return rows; } private List<DataTableRow> transposedListOfDatesAndCalWithHeader() { List<DataTableRow> rows = new ArrayList<DataTableRow>(); rows.add(new DataTableRow(NO_COMMENTS, asList("Birth Date", "1957-05-10", ""), 1)); rows.add(new DataTableRow(NO_COMMENTS, asList("Death Cal", "1979-02-02", ""), 2)); return rows; } private List<DataTableRow> transposedListOfDatesAndNamesWithHeader() { List<DataTableRow> rows = new ArrayList<DataTableRow>(); rows.add(new DataTableRow(NO_COMMENTS, asList("Birth Date", "1957-05-10"), 1)); rows.add(new DataTableRow(NO_COMMENTS, asList("Name", "Sid Vicious"), 2)); return rows; } private List<DataTableRow> transposedListOfDoublesWithoutHeader() { List<DataTableRow> rows = new ArrayList<DataTableRow>(); rows.add(new DataTableRow(NO_COMMENTS, asList("100.5", "0.5", "1000"), 1)); rows.add(new DataTableRow(NO_COMMENTS, asList("99.5", "-0.5", "999"), 2)); return rows; } private Date sidsBirthday() { Calendar sidsBirthday = Calendar.getInstance(); sidsBirthday.set(1957, 4, 10, 0, 0, 0); sidsBirthday.set(Calendar.MILLISECOND, 0); return sidsBirthday.getTime(); } private Calendar sidsDeathcal() { Calendar sidsDeathcal = Calendar.getInstance(); sidsDeathcal.set(1979, 1, 2, 0, 0, 0); sidsDeathcal.set(Calendar.MILLISECOND, 0); return sidsDeathcal; } public static class UserPojo { private Date birthDate; private Calendar deathCal; } @XStreamConverter(JavaBeanConverter.class) public static class UserBean { private Date birthDateX; public Date getBirthDate() { return this.birthDateX; } public void setBirthDate(Date birthDate) { this.birthDateX = birthDate; } } public static class UserWithNameField { public Name name; public Date birthDate; } public static class PrimitiveContainer { public Integer number; public Boolean bool; public boolean bool2; } @XStreamConverter(NameConverter.class) public static class Name { public String first; public String last; } public static class NameConverter extends Transformer<Name> { @Override public Name transform(String value) { Name name = new Name(); String[] firstLast = value.split(" "); name.first = firstLast[0]; name.last = firstLast[1]; return name; } } }