cucumber.runtime.table.TableDiffer Maven / Gradle / Ivy
package cucumber.runtime.table;
import cucumber.api.DataTable;
import cucumber.deps.difflib.Delta;
import cucumber.deps.difflib.DiffUtils;
import cucumber.deps.difflib.Patch;
import gherkin.pickles.PickleCell;
import gherkin.pickles.PickleRow;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import static cucumber.runtime.table.DataTableDiff.DiffType;
import static java.util.AbstractMap.SimpleEntry;
public class TableDiffer {
private final DataTable from;
private final DataTable to;
public TableDiffer(DataTable fromTable, DataTable toTable) {
checkColumns(fromTable, toTable);
this.from = fromTable;
this.to = toTable;
}
private void checkColumns(DataTable a, DataTable b) {
if (a.topCells().size() != b.topCells().size() && !b.topCells().isEmpty()) {
throw new IllegalArgumentException("Tables must have equal number of columns:\n" + a + "\n" + b);
}
}
public void calculateDiffs() throws TableDiffException {
Patch patch = DiffUtils.diff(from.diffableRows(), to.diffableRows());
List deltas = patch.getDeltas();
if (!deltas.isEmpty()) {
Map deltasByLine = createDeltasByLine(deltas);
throw new TableDiffException(from, to, createTableDiff(deltasByLine));
}
}
public void calculateUnorderedDiffs() throws TableDiffException {
boolean isDifferent = false;
List> diffTableRows = new ArrayList>();
List> missingRow = new ArrayList>();
ArrayList> extraRows = new ArrayList>();
// 1. add all "to" row in extra table
// 2. iterate over "from", when a common row occurs, remove it from extraRows
// finally, only extra rows are kept and in same order that in "to".
extraRows.addAll(to.raw());
for (PickleRow r : from.getPickleRows()) {
if (!to.raw().contains(getCellValues(r))) {
missingRow.add(getCellValues(r));
diffTableRows.add(
new SimpleEntry(new PickleRow(r.getCells()), DiffType.DELETE));
isDifferent = true;
} else {
diffTableRows.add(
new SimpleEntry(new PickleRow(r.getCells()), DiffType.NONE));
extraRows.remove(getCellValues(r));
}
}
for (List e : extraRows) {
diffTableRows.add(
new SimpleEntry(new PickleRow(convertToPickleCells(e)), DiffType.INSERT));
isDifferent = true;
}
if (isDifferent) {
throw new TableDiffException(from, to, DataTableDiff.create(diffTableRows, from.getTableConverter()));
}
}
private List convertToPickleCells(List e) {
List cells = new ArrayList(e.size());
for (String value : e) {
cells.add(new PickleCell(null, value));
}
return cells;
}
private List getCellValues(PickleRow r) {
List values = new ArrayList(r.getCells().size());
for (PickleCell cell : r.getCells()) {
values.add(cell.getValue());
}
return values;
}
private Map createDeltasByLine(List deltas) {
Map deltasByLine = new HashMap();
for (Delta delta : deltas) {
deltasByLine.put(delta.getOriginal().getPosition(), delta);
}
return deltasByLine;
}
private DataTable createTableDiff(Map deltasByLine) {
List> diffTableRows = new ArrayList>();
List> rows = from.raw();
for (int i = 0; i < rows.size(); i++) {
Delta delta = deltasByLine.get(i);
if (delta == null) {
diffTableRows.add(new SimpleEntry(from.getPickleRows().get(i), DiffType.NONE));
} else {
addRowsToTableDiff(diffTableRows, delta);
// skipping lines involved in a delta
if (delta.getType() == Delta.TYPE.CHANGE || delta.getType() == Delta.TYPE.DELETE) {
i += delta.getOriginal().getLines().size() - 1;
} else {
diffTableRows.add(new SimpleEntry(from.getPickleRows().get(i), DiffType.NONE));
}
}
}
// Can have new lines at end
Delta remainingDelta = deltasByLine.get(rows.size());
if (remainingDelta != null) {
addRowsToTableDiff(diffTableRows, remainingDelta);
}
return DataTableDiff.create(diffTableRows, from.getTableConverter());
}
private void addRowsToTableDiff(List> diffTableRows, Delta delta) {
markChangedAndDeletedRowsInOriginalAsMissing(diffTableRows, delta);
markChangedAndInsertedRowsInRevisedAsNew(diffTableRows, delta);
}
private void markChangedAndDeletedRowsInOriginalAsMissing(List> diffTableRows, Delta delta) {
List deletedLines = (List) delta.getOriginal().getLines();
for (DiffableRow row : deletedLines) {
diffTableRows.add(new SimpleEntry(new PickleRow(row.row.getCells()), DiffType.DELETE));
}
}
private void markChangedAndInsertedRowsInRevisedAsNew(List> diffTableRows, Delta delta) {
List insertedLines = (List) delta.getRevised().getLines();
for (DiffableRow row : insertedLines) {
diffTableRows.add(new SimpleEntry(new PickleRow(row.row.getCells()), DiffType.INSERT));
}
}
}