TableParsers.java
package org.jbehave.core.model;
import java.util.ArrayList;
import java.util.Deque;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.function.UnaryOperator;
import java.util.regex.Matcher;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.text.translate.CharSequenceTranslator;
import org.apache.commons.text.translate.LookupTranslator;
import org.jbehave.core.configuration.Keywords;
import org.jbehave.core.i18n.LocalizedKeywords;
import org.jbehave.core.model.ExamplesTable.TableProperties;
import org.jbehave.core.model.ExamplesTable.TablePropertiesQueue;
import org.jbehave.core.model.ExamplesTable.TableRows;
import org.jbehave.core.steps.ParameterConverters;
public class TableParsers {
private static final String ROW_SEPARATOR_PATTERN = "\r?\n";
private static final CharSequenceTranslator UNESCAPE_TRANSLATOR;
static {
final Map<CharSequence, CharSequence> unescapeMapping = new HashMap<>();
unescapeMapping.put("\\\\", "\\");
unescapeMapping.put("\\", StringUtils.EMPTY);
unescapeMapping.put("\\n", "\n");
unescapeMapping.put("\\r", "\r");
UNESCAPE_TRANSLATOR = new LookupTranslator(unescapeMapping);
}
private final Keywords keywords;
private final ParameterConverters parameterConverters;
private final Optional<String> defaultNullPlaceholder;
public TableParsers(ParameterConverters parameterConverters) {
this(new LocalizedKeywords(), parameterConverters);
}
public TableParsers(Keywords keywords, ParameterConverters parameterConverters) {
this(keywords, parameterConverters, Optional.empty());
}
public TableParsers(Keywords keywords, ParameterConverters parameterConverters,
Optional<String> defaultNullPlaceholder) {
this.keywords = keywords;
this.parameterConverters = parameterConverters;
this.defaultNullPlaceholder = defaultNullPlaceholder;
}
public TablePropertiesQueue parseProperties(String tableAsString) {
Deque<TableProperties> properties = new LinkedList<>();
String tableWithoutProperties = tableAsString.trim();
Matcher matcher = ExamplesTable.INLINED_PROPERTIES_PATTERN.matcher(tableWithoutProperties);
while (matcher.matches()) {
String propertiesAsString = matcher.group(1);
propertiesAsString = StringUtils.replace(propertiesAsString, "\\{", "{");
propertiesAsString = StringUtils.replace(propertiesAsString, "\\}", "}");
properties.add(new TableProperties(propertiesAsString, keywords, parameterConverters));
tableWithoutProperties = matcher.group(2).trim();
matcher = ExamplesTable.INLINED_PROPERTIES_PATTERN.matcher(tableWithoutProperties);
}
if (properties.isEmpty()) {
properties.add(new TableProperties("", keywords, parameterConverters));
}
return new TablePropertiesQueue(tableWithoutProperties, properties);
}
public TableRows parseRows(String tableAsString, TableProperties properties) {
List<String> headers = new ArrayList<>();
List<List<String>> rows = new ArrayList<>();
for (String rowLine : tableAsString.split(ROW_SEPARATOR_PATTERN)) {
String trimmedRowLine = rowLine.trim();
// skip ignorable or empty lines
if (!trimmedRowLine.startsWith(properties.getIgnorableSeparator()) && !trimmedRowLine.isEmpty()) {
if (headers.isEmpty()) {
headers.addAll(parseRow(trimmedRowLine, true, properties));
} else {
List<String> cells = parseRow(trimmedRowLine, false, properties);
if (cells.size() > headers.size()) {
cells = cells.subList(0, headers.size());
}
rows.add(cells);
}
}
}
return new TableRows(headers, rows);
}
public List<String> parseRow(String rowAsString, boolean header, TableProperties properties) {
String separator = header ? properties.getHeaderSeparator() : properties.getValueSeparator();
String commentSeparator = properties.getCommentSeparator();
Optional<String> nullPlaceholder = properties.getNullPlaceholder().map(Optional::of).orElse(
defaultNullPlaceholder);
UnaryOperator<String> trimmer = properties.isTrim() ? String::trim : UnaryOperator.identity();
boolean processEscapeSequences = properties.isProcessEscapeSequences();
String[] cells = StringUtils.splitByWholeSeparatorPreserveAllTokens(rowAsString.trim(), separator);
List<String> row = new ArrayList<>(cells.length);
for (int i = 0; i < cells.length; i++) {
String cell = cells[i];
cell = StringUtils.substringBefore(cell, commentSeparator);
if ((i == 0 || i == cells.length - 1) && cell.isEmpty()) {
continue;
}
String trimmedCell = trimmer.apply(cell);
if (processEscapeSequences) {
trimmedCell = UNESCAPE_TRANSLATOR.translate(trimmedCell);
}
row.add(nullPlaceholder.filter(trimmedCell::equals).isPresent() ? null : trimmedCell);
}
return row;
}
}