All Downloads are FREE. Search and download functionalities are using the official Maven repository.

cucumber.runtime.table.TableDiffer Maven / Gradle / Ivy

There is a newer version: 7.18.1
Show newest version
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));
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy