// 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.slimTables;
import fitnesse.responders.run.slimResponder.SlimTestContext;
import java.util.*;
public class DecisionTable extends SlimTable {
private static final String instancePrefix = "decisionTable";
private Set<String> dontReportExceptionsInTheseInstructions = new HashSet<String>();
public DecisionTable(Table table, String id, SlimTestContext context) {
super(table, id, context);
}
protected String getTableType() {
return instancePrefix;
}
public void appendInstructions() {
if (table.getRowCount() == 2)
throw new SyntaxError("DecisionTables should have at least three rows.");
String scenarioName = getScenarioName();
ScenarioTable scenario = getTestContext().getScenario(scenarioName);
if (scenario != null) {
new ScenarioCaller().call(scenario);
} else {
new FixtureCaller().call(getFixtureName());
}
}
private String getScenarioName() {
StringBuffer nameBuffer = new StringBuffer();
for (int nameCol = 0; nameCol < table.getColumnCountInRow(0); nameCol += 2) {
if (nameCol == 0)
nameBuffer.append(getFixtureName(table.getCellContents(nameCol, 0)));
else
nameBuffer.append(table.getCellContents(nameCol, 0));
nameBuffer.append(" ");
}
return Disgracer.disgraceClassName(nameBuffer.toString().trim());
}
public void evaluateReturnValues(Map<String, Object> returnValues) {
}
public boolean shouldIgnoreException(String resultKey, String resultString) {
boolean shouldNotReport = dontReportExceptionsInTheseInstructions.contains(resultKey);
boolean isNoSuchMethodException = resultString.indexOf("NO_METHOD_IN_CLASS") != -1;
return shouldNotReport && isNoSuchMethodException;
}
private class DecisionTableCaller {
protected Map<String, Integer> vars = new HashMap<String, Integer>();
protected Map<String, Integer> funcs = new HashMap<String, Integer>();
protected List<String> varsLeftToRight = new ArrayList<String>();
protected List<String> funcsLeftToRight = new ArrayList<String>();
protected int columnHeaders;
protected void gatherFunctionsAndVariablesFromColumnHeader() {
columnHeaders = table.getColumnCountInRow(1);
for (int col = 0; col < columnHeaders; col++)
putColumnHeaderInFunctionOrVariableList(col);
}
private void putColumnHeaderInFunctionOrVariableList(int col) {
String cell = table.getCellContents(col, 1);
if (cell.endsWith("?") || cell.endsWith("!")) {
String funcName = cell.substring(0, cell.length() - 1);
funcsLeftToRight.add(funcName);
funcs.put(funcName, col);
} else {
varsLeftToRight.add(cell);
vars.put(cell, col);
}
}
protected void checkRow(int row) {
int columns = table.getColumnCountInRow(row);
if (columns < columnHeaders)
throw new SyntaxError(
String.format("Table has %d header column(s), but row %d only has %d column(s).",
columnHeaders, row, columns
)
);
}
}
private class ScenarioCaller extends DecisionTableCaller {
public void call(ScenarioTable scenario) {
gatherFunctionsAndVariablesFromColumnHeader();
for (int row = 2; row < table.getRowCount(); row++)
callScenarioForRow(scenario, row);
}
private void callScenarioForRow(ScenarioTable scenario, int row) {
checkRow(row);
scenario.call(getArgumentsForRow(row), DecisionTable.this, row);
}
private Map<String, String> getArgumentsForRow(int row) {
Map<String, String> scenarioArguments = new HashMap<String, String>();
for (String var : vars.keySet()) {
String disgracedVar = Disgracer.disgraceMethodName(var);
int col = vars.get(var);
String valueToSet = table.getUnescapedCellContents(col, row);
scenarioArguments.put(disgracedVar, valueToSet);
}
return scenarioArguments;
}
}
private class FixtureCaller extends DecisionTableCaller {
public void call(String fixtureName) {
constructFixture(fixtureName);
dontReportExceptionsInTheseInstructions.add(callFunction(getTableName(), "table", tableAsList()));
if (table.getRowCount() > 2)
invokeRows();
}
private void invokeRows() {
callUnreportedFunction("beginTable");
gatherFunctionsAndVariablesFromColumnHeader();
for (int row = 2; row < table.getRowCount(); row++)
invokeRow(row);
callUnreportedFunction("endTable");
}
private void invokeRow(int row) {
checkRow(row);
callUnreportedFunction("reset");
setVariables(row);
callUnreportedFunction("execute");
callFunctions(row);
}
private void callUnreportedFunction(String functionName) {
dontReportExceptionsInTheseInstructions.add(callFunction(getTableName(), functionName));
}
private void callFunctions(int row) {
for (String functionName : funcsLeftToRight) {
callFunctionInRow(functionName, row);
}
}
private void callFunctionInRow(String functionName, int row) {
int col = funcs.get(functionName);
String assignedSymbol = ifSymbolAssignment(row, col);
if (assignedSymbol != null) {
addExpectation(new SymbolAssignmentExpectation(assignedSymbol, getInstructionTag(), col, row));
callAndAssign(assignedSymbol, functionName);
} else {
setFunctionCallExpectation(col, row);
callFunction(getTableName(), functionName);
}
}
private void setFunctionCallExpectation(int col, int row) {
table.getCellContents(col, row);
addExpectation(new ReturnedValueExpectation(getInstructionTag(), col, row));
}
private void setVariables(int row) {
for (String var : varsLeftToRight) {
int col = vars.get(var);
String valueToSet = table.getUnescapedCellContents(col, row);
setVariableExpectation(col, row);
List<Object> setInstruction = prepareInstruction();
addCall(setInstruction, getTableName(), "set" + " " + var);
setInstruction.add(valueToSet);
addInstruction(setInstruction);
}
}
private void setVariableExpectation(int col, int row) {
addExpectation(new VoidReturnExpectation(getInstructionTag(), col, row));
}
}
}