package org.jbehave.core.model;
import java.beans.BeanInfo;
import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.beans.MethodDescriptor;
import java.io.OutputStream;
import java.io.PrintStream;
import java.lang.reflect.Method;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import org.apache.commons.io.output.ByteArrayOutputStream;
import org.apache.commons.lang.builder.ToStringBuilder;
import org.apache.commons.lang.builder.ToStringStyle;
import org.jbehave.core.annotations.AsParameters;
import org.jbehave.core.annotations.Parameter;
import org.jbehave.core.model.ExamplesTable.RowNotFound;
import org.jbehave.core.model.TableTransformers.TableTransformer;
import org.jbehave.core.steps.ConvertedParameters.ValueNotFound;
import org.jbehave.core.steps.ParameterConverters;
import org.jbehave.core.steps.ParameterConverters.MethodReturningConverter;
import org.jbehave.core.steps.Parameters;
import org.junit.Test;
import static java.util.Arrays.asList;
import static org.codehaus.plexus.util.StringUtils.isBlank;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.not;
public class ExamplesTableBehaviour {
private String tableAsString = "|one|two|\n" + "|11|12|\n" + "|21|22|\n";
private String tableWithSpacesAsString = "|one |two | |\n" + "|11 |12 | |\n" + "| 21| 22| |\n";
private String landscapeTableAsString = "|one|11|21|\n" + "|two|12|22|\n";
private String wikiTableAsString = "||one||two||\n" + "|11|12|\n" + "|21|22|\n";
private String tableWithCommentsAsString = "|---------|\n" + "|one|two|\n" + "|-- A comment --|\n" + "|11|12|\n"
+ "|-- Another comment --|\n" + "|21|22|\n";
@Test
public void shouldParseTableWithDefaultSeparators() {
ExamplesTable table = new ExamplesTable(tableAsString);
ensureColumnOrderIsPreserved(table);
assertThat(table.asString(), equalTo(tableAsString));
}
@Test
public void shouldParseTableWithDifferentSeparators() {
String headerSeparator = "||";
String valueSeparator = "|";
String tableWithCustomSeparator = wikiTableAsString;
ExamplesTable table = new ExamplesTable(tableWithCustomSeparator, headerSeparator, valueSeparator);
assertThat(table.getHeaderSeparator(), equalTo(headerSeparator));
assertThat(table.getValueSeparator(), equalTo(valueSeparator));
ensureColumnOrderIsPreserved(table);
assertThat(table.asString(), equalTo(tableWithCustomSeparator));
}
@Test
public void shouldParseTableWithDifferentCustomSeparators() {
String headerSeparator = "!!";
String valueSeparator = "!";
String tableWithCustomSeparator = wikiTableAsString.replace("|", "!");
ExamplesTable table = new ExamplesTable(tableWithCustomSeparator, headerSeparator, valueSeparator);
assertThat(table.getHeaderSeparator(), equalTo(headerSeparator));
assertThat(table.getValueSeparator(), equalTo(valueSeparator));
ensureColumnOrderIsPreserved(table);
assertThat(table.asString(), equalTo("!!one!!two!!\n!11!12!\n!21!22!\n"));
}
@Test
public void shouldTrimTableBeforeParsing() {
String untrimmedTableAsString = "\n \n" + tableAsString + "\n \n";
ExamplesTable table = new ExamplesTable(untrimmedTableAsString);
ensureColumnOrderIsPreserved(table);
assertThat(table.asString(), equalTo("|one|two|\n|11|12|\n|21|22|\n"));
}
@Test
public void shouldParseTableWithCommentsInValues() {
String tableWithEmptyValues = "{commentSeparator=#}\n|one #comment|two|\n |11 #comment|12 #comment|\n |21|22|\n";
ExamplesTable table = new ExamplesTable(tableWithEmptyValues);
assertThat(table.getRowCount(), equalTo(2));
for (Parameters row : table.getRowsAsParameters()) {
Map<String, String> values = row.values();
assertThat(values.size(), equalTo(2));
for (String column : values.keySet()) {
assertThat(values.get(column), not(containsString("#comment")));
}
}
assertThat(table.asString(), equalTo("{commentSeparator=#}\n|one|two|\n|11|12|\n|21|22|\n"));
}
@Test
public void shouldParseTableWithUntrimmedCommentsInValues() {
String tableWithEmptyValues = "{commentSeparator=#, trim=false}\n|one #comment|two|\n |11 #comment|12 #comment|\n |21|22|\n";
ExamplesTable table = new ExamplesTable(tableWithEmptyValues);
assertThat(table.getRowCount(), equalTo(2));
for (Parameters row : table.getRowsAsParameters()) {
Map<String, String> values = row.values();
assertThat(values.size(), equalTo(2));
for (String column : values.keySet()) {
assertThat(values.get(column), not(containsString("#comment")));
}
}
assertThat(table.asString(), equalTo("{commentSeparator=#, trim=false}\n|one |two|\n|11 |12 |\n|21|22|\n"));
}
@Test
public void shouldParseEmptyTable() {
String tableAsString = "";
ExamplesTable table = new ExamplesTable(tableAsString);
assertThat(table.getHeaders().size(), equalTo(0));
assertThat(table.getRows().size(), equalTo(0));
assertThat(table.getRowsAsParameters().size(), equalTo(0));
assertThat(table.asString(), equalTo(tableAsString));
}
@Test
public void shouldParseTableWithBlankValues() {
String tableWithEmptyValues = "|one|two|\n |||\n | ||\n || |\n";
ExamplesTable table = new ExamplesTable(tableWithEmptyValues);
assertThat(table.getRowCount(), equalTo(3));
for (Parameters row : table.getRowsAsParameters()) {
Map<String, String> values = row.values();
assertThat(values.size(), equalTo(2));
for (String column : values.keySet()) {
assertThat(isBlank(values.get(column)), is(true));
}
}
assertThat(table.asString(), equalTo("|one|two|\n|||\n|||\n|||\n"));
}
@Test
public void shouldParseTableWithoutLeftBoundarySeparator() {
String tableAsString = "one|two|\n 11|12|\n 21|22|\n";
ExamplesTable table = new ExamplesTable(tableAsString);
ensureColumnOrderIsPreserved(table);
assertThat(table.asString(), equalTo("|one|two|\n|11|12|\n|21|22|\n"));
}
@Test
public void shouldParseTableWithoutRightBoundarySeparator() {
String tableAsString = "|one|two\n |11|12\n |21|22\n";
ExamplesTable table = new ExamplesTable(tableAsString);
ensureColumnOrderIsPreserved(table);
assertThat(table.asString(), equalTo("|one|two|\n|11|12|\n|21|22|\n"));
}
@Test
public void shouldParseTableWithoutAnyBoundarySeparators() {
String tableAsString = "one|two\n 11|12\n 21|22\n";
ExamplesTable table = new ExamplesTable(tableAsString);
ensureColumnOrderIsPreserved(table);
assertThat(table.asString(), equalTo("|one|two|\n|11|12|\n|21|22|\n"));
}
@Test
public void shouldParseTablePreservingWhitespace() {
String tableWithProperties = "{trim=false}\n" + tableWithSpacesAsString;
ExamplesTable table = new ExamplesTable(tableWithProperties);
Properties properties = table.getProperties();
assertThat(properties.getProperty("trim"), equalTo("false"));
ensureWhitespaceIsPreserved(table);
assertThat(table.asString(), equalTo("{trim=false}\n|one |two | |\n|11 |12 | |\n| 21| 22| |\n"));
}
@Test
public void shouldParseTableWithSeparatorsSpecifiedViaProperties() {
String tableWithProperties = "{ignorableSeparator=!--,headerSeparator=!,valueSeparator=!}\n"
+ tableWithCommentsAsString.replace("|", "!");
ExamplesTable table = new ExamplesTable(tableWithProperties);
Properties properties = table.getProperties();
assertThat(properties.getProperty("ignorableSeparator"), equalTo("!--"));
assertThat(properties.getProperty("headerSeparator"), equalTo("!"));
assertThat(properties.getProperty("valueSeparator"), equalTo("!"));
ensureColumnOrderIsPreserved(table);
}
@Test
public void shouldParseTableAsLandscape() {
String tableWithProperties = "{transformer=FROM_LANDSCAPE}\n" + landscapeTableAsString;
TableTransformers tableTransformers = new TableTransformers();
ExamplesTable table = new ExamplesTableFactory(tableTransformers).createExamplesTable(tableWithProperties);
Properties properties = table.getProperties();
assertThat(properties.getProperty("transformer"), equalTo("FROM_LANDSCAPE"));
ensureColumnOrderIsPreserved(table);
}
@Test
public void shouldParseTableWithCustomTransformerSpecifiedViaProperties() {
String tableWithProperties = "{transformer=myTransformer, trim=false}\n" + tableWithCommentsAsString;
TableTransformers tableTransformers = new TableTransformers();
tableTransformers.useTransformer("myTransformer", new TableTransformer() {
public String transform(String tableAsString, Properties properties) {
return tableWithSpacesAsString;
}
});
ExamplesTable table = new ExamplesTableFactory(tableTransformers).createExamplesTable(tableWithProperties);
Properties properties = table.getProperties();
assertThat(properties.getProperty("transformer"), equalTo("myTransformer"));
ensureWhitespaceIsPreserved(table);
}
private void ensureColumnOrderIsPreserved(ExamplesTable table) {
assertThat(table.getHeaders(), equalTo(asList("one", "two")));
List<Map<String, String>> rows = table.getRows();
assertThat(rows.size(), equalTo(2));
ensureRowContentIs(rows, 0, asList("11", "12"));
ensureRowContentIs(rows, 1, asList("21", "22"));
ensureCellContentIs(table, 0, "one", "11");
ensureCellContentIs(table, 0, "two", "12");
ensureCellContentIs(table, 1, "one", "21");
ensureCellContentIs(table, 1, "two", "22");
}
private void ensureWhitespaceIsPreserved(ExamplesTable table) {
assertThat(table.getHeaders(), equalTo(asList("one ", "two ", " ")));
List<Map<String, String>> rows = table.getRows();
assertThat(rows.size(), equalTo(2));
ensureRowContentIs(rows, 0, asList("11 ", "12 ", " "));
ensureRowContentIs(rows, 1, asList(" 21", " 22", " "));
ensureCellContentIs(table, 0, "one ", "11 ");
ensureCellContentIs(table, 0, "two ", "12 ");
ensureCellContentIs(table, 0, " ", " ");
ensureCellContentIs(table, 1, "one ", " 21");
ensureCellContentIs(table, 1, "two ", " 22");
ensureCellContentIs(table, 1, " ", " ");
}
private void ensureRowContentIs(List<Map<String, String>> rows, int row, List<String> expected) {
assertThat(new ArrayList<String>(rows.get(row).values()), equalTo(expected));
}
private void ensureCellContentIs(ExamplesTable table, int row, String header, String value) {
assertThat(table.getRow(row).get(header), equalTo(value));
}
@Test
public void shouldConvertParameterValuesOfTableRow() throws Exception {
// Given
ParameterConverters parameterConverters = new ParameterConverters();
parameterConverters.addConverters(new MethodReturningConverter(methodFor("convertDate"), this));
ExamplesTableFactory factory = new ExamplesTableFactory(parameterConverters);
// When
String tableAsString = "|one|two|\n|11|22|\n|1/1/2010|2/2/2010|";
ExamplesTable examplesTable = factory.createExamplesTable(tableAsString);
// Then
Parameters integers = examplesTable.getRowAsParameters(0);
assertThat(integers.valueAs("one", Integer.class), equalTo(11));
assertThat(integers.valueAs("two", Integer.class), equalTo(22));
Parameters dates = examplesTable.getRowAsParameters(1);
assertThat(dates.valueAs("one", Date.class), equalTo(convertDate("1/1/2010")));
assertThat(dates.valueAs("two", Date.class), equalTo(convertDate("2/2/2010")));
}
@Test
public void shouldConvertParameterValuesOfTableRowWithDefaults() throws Exception {
// Given
ParameterConverters parameterConverters = new ParameterConverters();
parameterConverters.addConverters(new MethodReturningConverter(methodFor("convertDate"), this));
ExamplesTableFactory factory = new ExamplesTableFactory(parameterConverters);
// When
String tableDefaultsAsString = "|three|\n|99|";
ExamplesTable defaultsTable = factory.createExamplesTable(tableDefaultsAsString);
Parameters defaults = defaultsTable.getRowAsParameters(0);
String tableAsString = "|one|\n|11|\n|22|";
ExamplesTable examplesTable = factory.createExamplesTable(tableAsString).withDefaults(defaults);
// Then
Parameters firstRow = examplesTable.getRowAsParameters(0);
Map<String, String> firstRowValues = firstRow.values();
assertThat(firstRowValues.containsKey("one"), is(true));
assertThat(firstRow.valueAs("one", String.class), is("11"));
assertThat(firstRow.valueAs("one", Integer.class), is(11));
assertThat(firstRowValues.containsKey("three"), is(true));
assertThat(firstRow.valueAs("three", String.class), is("99"));
assertThat(firstRow.valueAs("three", Integer.class), is(99));
assertThat(firstRowValues.containsKey("XX"), is(false));
assertThat(firstRow.valueAs("XX", Integer.class, 13), is(13));
Parameters secondRow = examplesTable.getRowAsParameters(1);
Map<String, String> secondRowValues = secondRow.values();
assertThat(secondRowValues.containsKey("one"), is(true));
assertThat(secondRow.valueAs("one", String.class), is("22"));
assertThat(secondRow.valueAs("one", Integer.class), is(22));
assertThat(secondRowValues.containsKey("three"), is(true));
assertThat(secondRow.valueAs("three", String.class), is("99"));
assertThat(secondRow.valueAs("three", Integer.class), is(99));
assertThat(secondRowValues.containsKey("XX"), is(false));
assertThat(secondRow.valueAs("XX", Integer.class, 13), is(13));
}
@Test
public void shouldReplaceNamedParameterValues() throws Exception {
// Given
ExamplesTableFactory factory = new ExamplesTableFactory();
// When
String tableAsString = "|Name|Value|\n|name1|<value>|";
Map<String, String> namedParameters = new HashMap<String, String>();
namedParameters.put("<value>", "value1");
ExamplesTable table = factory.createExamplesTable(tableAsString).withNamedParameters(namedParameters);
// Then
Parameters firstRow = table.getRowsAsParameters(true).get(0);
Map<String, String> firstRowValues = firstRow.values();
assertThat(firstRowValues.containsKey("Value"), is(true));
assertThat(firstRow.valueAs("Value", String.class), is("value1"));
}
@Test
public void shouldMapParametersToType() throws Exception {
// Given
ExamplesTableFactory factory = new ExamplesTableFactory();
// When
String tableAsString = "|string|integer|\n|11|22|";
ExamplesTable examplesTable = factory.createExamplesTable(tableAsString);
// Then
for (MyParameters parameters : examplesTable.getRowsAs(MyParameters.class)) {
assertThat(parameters.string, equalTo("11"));
assertThat(parameters.integer, equalTo(22));
}
}
@Test
public void shouldMapParametersToTypeWithFieldMappings() throws Exception {
// Given
ExamplesTableFactory factory = new ExamplesTableFactory();
// When
String tableAsString = "|aString|anInteger|\n|11|22|";
ExamplesTable examplesTable = factory.createExamplesTable(tableAsString);
Map<String, String> nameMapping = new HashMap<String, String>();
nameMapping.put("aString", "string");
nameMapping.put("anInteger", "integer");
// Then
for (MyParameters parameters : examplesTable.getRowsAs(MyParameters.class, nameMapping)) {
assertThat(parameters.string, equalTo("11"));
assertThat(parameters.integer, equalTo(22));
}
}
@Test
public void shouldMapParametersToTypeWithAnnotatedFields() throws Exception {
// Given
ExamplesTableFactory factory = new ExamplesTableFactory();
// When
String tableAsString = "|aString|anInteger|\n|11|22|";
ExamplesTable examplesTable = factory.createExamplesTable(tableAsString);
// Then
for (MyParametersWithAnnotatedFields parameters : examplesTable.getRowsAs(MyParametersWithAnnotatedFields.class)) {
assertThat(parameters.string, equalTo("11"));
assertThat(parameters.integer, equalTo(22));
}
}
@Test
public void shouldThrowExceptionIfValuesOrRowsAreNotFound() throws Exception {
// Given
ParameterConverters parameterConverters = new ParameterConverters();
ExamplesTableFactory factory = new ExamplesTableFactory(parameterConverters);
// When
String tableAsString = "|one|two|\n|11|22|\n";
ExamplesTable examplesTable = factory.createExamplesTable(tableAsString);
// Then
Parameters integers = examplesTable.getRowAsParameters(0);
assertThat(integers.valueAs("one", Integer.class), equalTo(11));
try {
integers.valueAs("unknown", Integer.class);
} catch (ValueNotFound e) {
assertThat(e.getMessage(), equalTo("unknown"));
}
try {
examplesTable.getRowAsParameters(1);
} catch (RowNotFound e) {
assertThat(e.getMessage(), equalTo("1"));
}
}
@Test
public void shouldAllowAdditionAndModificationOfRowValues() throws Exception {
// Given
ParameterConverters parameterConverters = new ParameterConverters();
ExamplesTableFactory factory = new ExamplesTableFactory(parameterConverters);
// When
String tableAsString = "|one|two|\n|11|12|\n|21|22|";
ExamplesTable examplesTable = factory.createExamplesTable(tableAsString);
Map<String, String> values = new HashMap<String, String>();
values.put("one", "111");
values.put("three", "333");
examplesTable.withRowValues(0, values);
Map<String, String> otherValues = new HashMap<String, String>();
otherValues.put("two", "222");
examplesTable.withRowValues(1, otherValues);
// Then
Parameters firstRow = examplesTable.getRowAsParameters(0);
assertThat(firstRow.valueAs("one", Integer.class), equalTo(111));
assertThat(firstRow.valueAs("two", Integer.class), equalTo(12));
assertThat(firstRow.valueAs("three", Integer.class), equalTo(333));
Parameters secondRow = examplesTable.getRowAsParameters(1);
assertThat(secondRow.valueAs("one", Integer.class), equalTo(21));
assertThat(secondRow.valueAs("two", Integer.class), equalTo(222));
assertThat(secondRow.valueAs("three", String.class), equalTo(""));
assertThat(examplesTable.asString(), equalTo("|one|two|three|\n|111|12|333|\n|21|222||\n"));
}
@Test
public void shouldAllowBuildingOfTableFromContent() throws Exception {
// Given
ParameterConverters parameterConverters = new ParameterConverters();
ExamplesTableFactory factory = new ExamplesTableFactory(parameterConverters);
// When
String tableAsString = "|one|two|\n|11|12|\n|21|22|";
ExamplesTable originalTable = factory.createExamplesTable(tableAsString);
List<Map<String, String>> content = originalTable.getRows();
content.get(0).put("three", "13");
content.get(1).put("three", "23");
ExamplesTable updatedTable = originalTable.withRows(content);
// Then
assertThat(updatedTable.asString(), equalTo("|one|two|three|\n|11|12|13|\n|21|22|23|\n"));
}
@Test
public void shouldAllowOutputToPrintStream() throws Exception {
// Given
ParameterConverters parameterConverters = new ParameterConverters();
ExamplesTableFactory factory = new ExamplesTableFactory(parameterConverters);
// When
String tableAsString = "|one|two|\n|11|12|\n|21|22|\n";
ExamplesTable table = factory.createExamplesTable(tableAsString);
OutputStream out = new ByteArrayOutputStream();
PrintStream output = new PrintStream(out);
table.outputTo(output);
// Then
assertThat(out.toString(), equalTo(tableAsString));
}
@Test
public void shouldIgnoreEmptyLines() throws Exception {
// ignore blank lines
String tableWithEmptyLines = "|one|two|\n|a|b|\n\n|c|d|\n\r\n";
ExamplesTable table = new ExamplesTable(tableWithEmptyLines);
assertThat(table.getRowCount(), equalTo(2));
assertThat(table.asString(), equalTo("|one|two|\n|a|b|\n|c|d|\n"));
}
@Test
public void shouldIgnoreAllCommentLines() {
// ignore comment lines
ExamplesTable table = new ExamplesTable(tableWithCommentsAsString);
ensureColumnOrderIsPreserved(table);
assertThat(table.asString(), equalTo(tableAsString));
}
@Test
public void shouldHandleWrongNumberOfColumns() {
assertTableAsString("|a|b|\n|a|\n", "|a|b|\n|a||\n");
assertTableAsString("|a|b|\n|a|b|c|\n", "|a|b|\n|a|b|\n");
}
private void assertTableAsString(String tableAsString, String expectedTableAsString) {
assertThat(new ExamplesTable(tableAsString).asString(), equalTo(expectedTableAsString));
}
public Date convertDate(String value) throws ParseException {
return new SimpleDateFormat("dd/MM/yyyy").parse(value);
}
public static Method methodFor(String methodName) throws IntrospectionException {
BeanInfo beanInfo = Introspector.getBeanInfo(ExamplesTableBehaviour.class);
for (MethodDescriptor md : beanInfo.getMethodDescriptors()) {
if (md.getMethod().getName().equals(methodName)) {
return md.getMethod();
}
}
return null;
}
@AsParameters
public static class MyParameters {
private String string;
private Integer integer;
@Override
public String toString() {
return ToStringBuilder.reflectionToString(this, ToStringStyle.SHORT_PREFIX_STYLE);
}
}
@AsParameters
public static class MyParametersWithAnnotatedFields {
@Parameter(name = "aString")
private String string;
@Parameter(name = "anInteger")
private Integer integer;
@Override
public String toString() {
return ToStringBuilder.reflectionToString(this, ToStringStyle.SHORT_PREFIX_STYLE);
}
}
}