/src/fitnesse/testsystems/slim/tables/QueryTable.java
Java | 365 lines | 299 code | 64 blank | 2 comment | 59 complexity | 454a4ff52891025bc964d3ae5b3ad073 MD5 | raw file
Possible License(s): BSD-2-Clause, BSD-3-Clause, GPL-2.0
- // Copyright (C) 2003-2009 by Object Mentor, Inc. All rights reserved.
- // Released under the terms of the CPL Common Public License version 1.0.
- package fitnesse.testsystems.slim.tables;
- import java.util.*;
- import fitnesse.testsystems.ExecutionResult;
- import fitnesse.testsystems.TestResult;
- import fitnesse.testsystems.slim.SlimTestContext;
- import fitnesse.testsystems.slim.Table;
- import fitnesse.testsystems.slim.results.SlimExceptionResult;
- import fitnesse.testsystems.slim.results.SlimTestResult;
- import fitnesse.util.StringUtils;
- public class QueryTable extends SlimTable {
- private static final String COMMENT_COLUMN_MARKER = "#";
- protected List<String> fieldNames = new ArrayList<>();
- public QueryTable(Table table, String id, SlimTestContext testContext) {
- super(table, id, testContext);
- }
- @Override
- protected String getTableType() {
- return "queryTable";
- }
- public boolean matches(String actual, String expected) {
- if (actual == null || expected == null)
- return false;
- if (actual.equals(replaceSymbols(expected)))
- return true;
- Comparator c = new Comparator(actual, expected);
- return c.matches();
- }
- public SlimTestResult matchMessage(String actual, String expected) {
- if (actual == null)
- return SlimTestResult.fail("NULL");
- if (actual.equals(replaceSymbols(expected)))
- return SlimTestResult.pass(replaceSymbolsWithFullExpansion(expected));
- Comparator c = new Comparator(actual, expected);
- return c.evaluate();
- }
- @Override
- public List<SlimAssertion> getAssertions() throws SyntaxError {
- if (table.getRowCount() < 2)
- throw new SyntaxError("Query tables must have at least two rows.");
- assignColumns();
- SlimAssertion make = constructFixture(getFixtureName());
- SlimAssertion ti = makeAssertion(callFunction(getTableName(), "table", tableAsList()),
- new SilentReturnExpectation(0, 0));
- SlimAssertion qi = makeAssertion(callFunction(getTableName(), "query"),
- new QueryTableExpectation());
- return Arrays.asList(make, ti, qi);
- }
- private void assignColumns() {
- int cols = table.getColumnCountInRow(1);
- for (int col = 0; col < cols; col++)
- fieldNames.add(table.getCellContents(col, 1));
- }
- public class QueryTableExpectation implements SlimExpectation {
- @Override
- public TestResult evaluateExpectation(Object queryReturn) {
- SlimTestResult testResult;
- if (queryReturn == null) {
- testResult = SlimTestResult.testNotRun();
- } else if (queryReturn instanceof List) {
- testResult = new SlimTestResult(scanRowsForMatches((List<List<List<Object>>>) queryReturn));
- testResult.setVariables(getSymbolsToStore());
- } else {
- testResult = SlimTestResult.error(String.format("The query method returned: %s", queryReturn));
- table.updateContent(0, 0, testResult);
- getTestContext().increment(testResult.getExecutionResult());
- }
- return testResult;
- }
- @Override
- public SlimExceptionResult evaluateException(SlimExceptionResult exceptionResult) {
- table.updateContent(0, 0, exceptionResult);
- getTestContext().incrementErroredTestsCount();
- return exceptionResult;
- }
- }
- private ExecutionResult scanRowsForMatches(List<List<List<Object>>> queryResultList) {
- final QueryResults queryResults = new QueryResults(queryResultList);
- Collection<MatchedResult> potentialMatches = queryResults.scorePotentialMatches();
- List<MatchedResult> potentialMatchesByScore = new ArrayList<>(potentialMatches);
- Collections.sort(potentialMatchesByScore, MatchedResult.compareByScore());
- return markRows(queryResults, potentialMatchesByScore);
- }
- protected ExecutionResult markRows(QueryResults queryResults, Iterable<MatchedResult> potentialMatchesByScore) {
- List<Integer> unmatchedTableRows = unmatchedRows(table.getRowCount());
- unmatchedTableRows.remove(Integer.valueOf(0));
- unmatchedTableRows.remove(Integer.valueOf(1));
- List<Integer> unmatchedResultRows = unmatchedRows(queryResults.getRows().size());
- markMatchedRows(queryResults, potentialMatchesByScore, unmatchedTableRows, unmatchedResultRows);
- markMissingRows(unmatchedTableRows);
- markSurplusRows(queryResults, unmatchedResultRows);
- return !unmatchedTableRows.isEmpty() || !unmatchedResultRows.isEmpty() ? ExecutionResult.FAIL : ExecutionResult.PASS;
- }
- protected void markMatchedRows(QueryResults queryResults, Iterable<MatchedResult> potentialMatchesByScore, List<Integer> unmatchedTableRows, List<Integer> unmatchedResultRows) {
- while (!isEmpty(potentialMatchesByScore)) {
- MatchedResult bestMatch = takeBestMatch(potentialMatchesByScore);
- markFieldsInMatchedRow(bestMatch.tableRow, bestMatch.resultRow, queryResults);
- unmatchedTableRows.remove(bestMatch.tableRow);
- unmatchedResultRows.remove(bestMatch.resultRow);
- }
- }
- protected MatchedResult takeBestMatch(Iterable<MatchedResult> potentialMatchesByScore) {
- MatchedResult bestResult = potentialMatchesByScore.iterator().next();
- removeOtherwiseMatchedResults(potentialMatchesByScore, bestResult);
- return bestResult;
- }
- protected boolean isEmpty(Iterable<MatchedResult> iterable) {
- return !iterable.iterator().hasNext();
- }
- protected void removeOtherwiseMatchedResults(Iterable<MatchedResult> potentialMatchesByScore, MatchedResult bestResult) {
- Iterator<MatchedResult> iterator = potentialMatchesByScore.iterator();
- while (iterator.hasNext()) {
- MatchedResult otherResult = iterator.next();
- if (otherResult.tableRow.equals(bestResult.tableRow) || otherResult.resultRow.equals(bestResult.resultRow))
- iterator.remove();
- }
- }
- protected List<Integer> unmatchedRows(int rowCount) {
- List<Integer> result = new ArrayList<>(rowCount);
- for (int i = 0; i < rowCount; i++) {
- result.add(i);
- }
- return result;
- }
- protected void markMissingRows(List<Integer> missingRows) {
- for (int missingRow : missingRows) {
- markMissingRow(missingRow);
- }
- }
- protected void markMissingRow(int missingRow) {
- replaceAllvariablesInRow(missingRow);
- SlimTestResult testResult = SlimTestResult.fail(null, table.getCellContents(0, missingRow), "missing");
- table.updateContent(0, missingRow, testResult);
- getTestContext().increment(testResult.getExecutionResult());
- }
- protected void markSurplusRows(final QueryResults queryResults, List<Integer> unmatchedRows) {
- for (int unmatchedRow : unmatchedRows) {
- List<String> surplusRow = queryResults.getList(fieldNames, unmatchedRow);
- int newTableRow = table.addRow(surplusRow);
- SlimTestResult testResult = SlimTestResult.fail(surplusRow.get(0), null, "surplus");
- table.updateContent(0, newTableRow, testResult);
- getTestContext().increment(ExecutionResult.FAIL);
- markMissingFields(surplusRow, newTableRow);
- }
- }
- private void markMissingFields(List<String> surplusRow, int newTableRow) {
- for (int col = 0; col < surplusRow.size(); col++) {
- String surplusField = surplusRow.get(col);
- if (surplusField == null) {
- String fieldName = fieldNames.get(col);
- SlimTestResult testResult = SlimTestResult.fail(String.format("field %s not present", fieldName));
- table.updateContent(col, newTableRow, testResult);
- getTestContext().increment(testResult.getExecutionResult());
- }
- }
- }
- protected void replaceAllvariablesInRow(int tableRow) {
- int columns = table.getColumnCountInRow(tableRow);
- for (int col = 0; col < columns; col++) {
- String contents = table.getCellContents(col, tableRow);
- table.substitute(col, tableRow, replaceSymbolsWithFullExpansion(contents));
- }
- }
- protected void markFieldsInMatchedRow(int tableRow, int matchedRow, QueryResults queryResults) {
- int columns = table.getColumnCountInRow(tableRow);
- for (int col = 0; col < columns; col++) {
- markField(tableRow, matchedRow, col, queryResults);
- }
- }
- protected TestResult markField(int tableRow, int matchedRow, int col, QueryResults queryResults) {
- if (col >= fieldNames.size())
- return null; // ignore strange table geometry.
- String fieldName = fieldNames.get(col);
- String actualValue = queryResults.getCell(fieldName, matchedRow);
- String expectedValue = table.getCellContents(col, tableRow);
- SlimTestResult testResult;
- if (fieldName.startsWith(COMMENT_COLUMN_MARKER))
- testResult = SlimTestResult.plain();
- else if (actualValue == null)
- testResult = SlimTestResult.fail(String.format("field %s not present", fieldName), expectedValue);
- else if (expectedValue == null || expectedValue.isEmpty())
- testResult = SlimTestResult.ignore(actualValue);
- else {
- String symbolName = isSymbolAssignment(expectedValue);
- if (symbolName != null) {
- setSymbol(symbolName, actualValue, true);
- testResult = SlimTestResult.ignore(String.format("$%s<-[%s]", symbolName, actualValue));
- } else {
- testResult = matchMessage(actualValue, expectedValue);
- if (testResult == null)
- testResult = SlimTestResult.fail(actualValue, replaceSymbolsWithFullExpansion(expectedValue));
- else if (testResult.getExecutionResult() == ExecutionResult.PASS)
- testResult = markMatch(tableRow, matchedRow, col, testResult.getMessage());
- }
- }
- table.updateContent(col, tableRow, testResult);
- getTestContext().increment(testResult.getExecutionResult());
- return testResult;
- }
- protected SlimTestResult markMatch(int tableRow, int matchedRow, int col, String message) {
- return SlimTestResult.pass(message);
- }
- protected class QueryResults {
- private List<QueryResultRow> rows = new ArrayList<>();
- public QueryResults(List<List<List<Object>>> queryResultTable) {
- for (int i = 0; i < queryResultTable.size(); i++) {
- rows.add(new QueryResultRow(i, queryResultTable.get(i)));
- }
- rows = Collections.unmodifiableList(rows);
- }
- public Collection<MatchedResult> scorePotentialMatches() {
- Collection<MatchedResult> result = new ArrayList<>();
- int rows = table.getRowCount();
- for (int tableRow = 2; tableRow < rows; tableRow++)
- result.addAll(new QueryMatcher(fieldNames).scoreMatches(tableRow));
- return result;
- }
- public List<String> getList(List<String> fieldNames, int row) {
- List<String> result = new ArrayList<>();
- for (String name : fieldNames)
- result.add(rows.get(row).get(name));
- return result;
- }
- public String getCell(String name, int row) {
- return rows.get(row).get(name);
- }
- public List<QueryResultRow> getRows() {
- return rows;
- }
- private class QueryMatcher {
- private final List<String> fields;
- private QueryMatcher(List<String> fields) {
- this.fields = fields;
- }
- public Collection<MatchedResult> scoreMatches(int tableRow) {
- Collection<MatchedResult> result = new ArrayList<>();
- for (QueryResultRow row : rows) {
- MatchedResult match = scoreMatch(table, tableRow, row);
- if (match.score > 0)
- result.add(match);
- }
- return result;
- }
- private MatchedResult scoreMatch(Table table, int tableRow, QueryResultRow row) {
- int score = 0;
- for (int fieldIndex = 0; fieldIndex < fields.size(); fieldIndex++) {
- String fieldName = fields.get(fieldIndex);
- if (!fieldName.startsWith(COMMENT_COLUMN_MARKER)) {
- String actualValue = row.get(fieldName);
- String expectedValue = table.getCellContents(fieldIndex, tableRow);
- if(isSymbolAssignment(expectedValue) != null) {
- continue;
- }
- if (matches(actualValue, expectedValue)) {
- score++;
- } else if (!StringUtils.isBlank(expectedValue)) {
- break;
- }
- }
- }
- return new MatchedResult(tableRow, row.index, score);
- }
- }
- private class QueryResultRow {
- private final int index;
- private final Map<String, String> values;
- public QueryResultRow(int index, List<List<Object>> values) {
- this.index = index;
- Map<String, String> rowMap = new HashMap<>();
- for (List<Object> columnPair : values) {
- String fieldName = (String) columnPair.get(0);
- String fieldValue = (String) columnPair.get(1);
- rowMap.put(fieldName, fieldValue);
- }
- this.values = rowMap;
- }
- public String get(String fieldName) {
- return values.get(fieldName);
- }
- }
- }
- protected static class MatchedResult {
- final Integer tableRow;
- final Integer resultRow;
- final int score;
- public MatchedResult(int tableRow, int resultRow, int score) {
- this.tableRow = tableRow;
- this.resultRow = resultRow;
- this.score = score;
- }
- public static java.util.Comparator<MatchedResult> compareByScore() {
- return new java.util.Comparator<MatchedResult>() {
- @Override
- public int compare(MatchedResult o1, MatchedResult o2) {
- return o2.score - o1.score;
- }
- };
- }
- }
- }