// 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.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import fitnesse.slim.instructions.Instruction;
import fitnesse.testsystems.TestExecutionException;
import fitnesse.testsystems.slim.SlimTestContext;
import fitnesse.testsystems.slim.Table;
public class DecisionTable extends SlimTable {
private static final String instancePrefix = "decisionTable";
protected MethodExtractor setterMethodExtractor;
protected MethodExtractor getterMethodExtractor;
protected boolean baselineDecisionTable = false;
public DecisionTable(Table table, String id, SlimTestContext context) {
super(table, id, context);
}
@Override
protected String getTableType() {
return instancePrefix;
}
@Override
public List<SlimAssertion> getAssertions() throws TestExecutionException {
if (table.getRowCount() == 2)
throw new SyntaxError("DecisionTables should have at least three rows.");
// or 1 if only the constructor of a class should be called
String scenarioName = getScenarioName();
ScenarioTable scenario = getTestContext().getScenario(scenarioName);
if (scenario != null) {
return new ScenarioCaller().call(scenario);
} else {
String fixtureName =getFixtureName();
scenario = getTestContext().getScenario(fixtureName);
if (scenario != null) {
return new ScenarioCallerWithConstuctorParameters().call(scenario);
} else {
setterMethodExtractor = prepareMethodExtractorIfNull(setterMethodExtractor,"SLIM_DT_SETTER");
getterMethodExtractor = prepareMethodExtractorIfNull(getterMethodExtractor,"SLIM_DT_GETTER");
return new FixtureCaller().call(fixtureName);
}
}
}
private String getScenarioName() {
StringBuilder nameBuffer = new StringBuilder();
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());
}
protected Instruction callAndAssign(String symbolName, String functionName) {
return callAndAssign(symbolName, getTableName(), functionName);
}
private MethodExtractor prepareMethodExtractorIfNull(MethodExtractor current, String sourceVariableName) throws SyntaxError{
if (current == null){
String setterString = this.getTestContext().getPageToTest().getVariable(sourceVariableName);
try{
if (setterString != null && !setterString.isEmpty() ) current = new MethodExtractor(setterString);
else{
current = new MethodExtractor();
}
}catch (Exception cause ){
SyntaxError sE = new SyntaxError(sourceVariableName+ " variable could not be parsed:\n"+setterString+"\nCause:"+cause.getMessage());
sE.initCause(cause);
throw sE;
}
}
return current;
}
private class ScenarioCaller extends DecisionTableCaller {
public ScenarioCaller() {
super(table, isBaselineDecisionTable());
}
public ArrayList<SlimAssertion> call(ScenarioTable scenario) throws TestExecutionException {
gatherFunctionsAndVariablesFromColumnHeader();
ArrayList<SlimAssertion> assertions = new ArrayList<>();
for (int row = 2; row < table.getRowCount(); row++){
assertions.addAll(callScenarioForRow(scenario, row));
assertions.addAll(callFunctions(row));
}
return assertions;
}
private List<SlimAssertion> callScenarioForRow(ScenarioTable scenario, int row) throws TestExecutionException {
checkRow(row);
return scenario.call(getArgumentsForRow(row), DecisionTable.this, row);
}
private List<SlimAssertion> callFunctions(int row) {
List<SlimAssertion> instructions = new ArrayList<>();
for (String functionName : funcStore.getLeftToRightAndResetColumnNumberIterator()) {
instructions.add(callFunctionInRow(functionName, row));
}
return instructions;
}
private SlimAssertion callFunctionInRow(String functionName, int row) {
int col = funcStore.getColumnNumber(functionName);
String name = Disgracer.disgraceMethodName(functionName);
String assignedSymbol = ifSymbolAssignment(col, row);
SlimAssertion assertion;
if (assignedSymbol != null) {
assertion= makeAssertion(callAndAssign(assignedSymbol, "scriptTable" + "Actor", "cloneSymbol", "$"+name),
new ReturnedSymbolExpectation(col, row, name, assignedSymbol));
} else {
assertion = makeAssertion(Instruction.NOOP_INSTRUCTION, new ReturnedSymbolExpectation(getDTCellContents(col, row), col, row, name));
}
return assertion;
}
private Map<String, String> getArgumentsForRow(int row) {
Map<String, String> scenarioArguments = new HashMap<>();
for (String var : constructorParameterStore.getLeftToRightAndResetColumnNumberIterator()) {
String disgracedVar = Disgracer.disgraceMethodName(var);
int col = constructorParameterStore.getColumnNumber(var);
String valueToSet = table.getCellContents(col, 0);
scenarioArguments.put(disgracedVar, valueToSet);
}
for (String var : varStore.getLeftToRightAndResetColumnNumberIterator()) {
String disgracedVar = Disgracer.disgraceMethodName(var);
int col = varStore.getColumnNumber(var);
String valueToSet = getDTCellContents(col, row);
scenarioArguments.put(disgracedVar, valueToSet);
}
return scenarioArguments;
}
}
private class ScenarioCallerWithConstuctorParameters extends ScenarioCaller {
public ScenarioCallerWithConstuctorParameters() {
super();
gatherConstructorParameters();
}
}
private class FixtureCaller extends DecisionTableCaller {
public FixtureCaller() {
super(table,isBaselineDecisionTable() );
}
public List<SlimAssertion> call(String fixtureName) throws SyntaxError {
final List<SlimAssertion> assertions = new ArrayList<>();
assertions.add(constructFixture(fixtureName));
assertions.add(makeAssertion(
callFunction(getTableName(), "table", tableAsList()),
new SilentReturnExpectation(0, 0)));
if (table.getRowCount() > 2)
assertions.addAll(invokeRows());
return assertions;
}
private List<SlimAssertion> invokeRows() throws SyntaxError {
List<SlimAssertion> assertions = new ArrayList<>();
assertions.add(callUnreportedFunction("beginTable", 0));
gatherFunctionsAndVariablesFromColumnHeader();
for (int row = 2; row < table.getRowCount(); row++)
assertions.addAll(invokeRow(row));
assertions.add(callUnreportedFunction("endTable", 0));
return assertions;
}
private List<SlimAssertion> invokeRow(int row) throws SyntaxError {
List<SlimAssertion> assertions = new ArrayList<>();
checkRow(row);
assertions.add(callUnreportedFunction("reset", row));
assertions.addAll(setVariables(row));
assertions.add(callUnreportedFunction("execute", row));
assertions.addAll(callFunctions(row));
return assertions;
}
private SlimAssertion callUnreportedFunction(String functionName, int row) {
return makeAssertion(callFunction(getTableName(), functionName),
new SilentReturnExpectation(0, row));
}
private List<SlimAssertion> callFunctions(int row) {
List<SlimAssertion> instructions = new ArrayList<>();
for (String functionName : funcStore.getLeftToRightAndResetColumnNumberIterator()) {
instructions.add(callFunctionInRow(functionName, row));
}
return instructions;
}
private SlimAssertion callFunctionInRow(String functionName, int row) {
int col = funcStore.getColumnNumber(functionName);
String assignedSymbol = ifSymbolAssignment(col, row);
SlimAssertion assertion;
Object[] args = new Object[] {};
MethodExtractorResult extractedGetter = getterMethodExtractor.findRule(functionName);
if(extractedGetter != null){
functionName = extractedGetter.methodName;
args = extractedGetter.mergeParameters(args);
}
if (assignedSymbol != null) {
assertion = makeAssertion(callAndAssign(assignedSymbol, getTableName(), functionName, args),
new SymbolAssignmentExpectation(assignedSymbol, col, row));
} else {
assertion = makeAssertion(callFunction(getTableName(), functionName, args),
new ReturnedValueExpectation(col, row, getDTCellContents(col, row)));
}
return assertion;
}
private List<SlimAssertion> setVariables(int row) {
List<SlimAssertion> assertions = new ArrayList<>();
for (String var : varStore.getLeftToRightAndResetColumnNumberIterator()) {
int col = varStore.getColumnNumber(var);
String valueToSet = getDTCellContents(col, row);
Object[] args = new Object[] {valueToSet};
MethodExtractorResult extractedSetter = setterMethodExtractor.findRule(var);
if(extractedSetter != null){
var = extractedSetter.methodName;
args = extractedSetter.mergeParameters(args);
}else{
// Default for Setter
var = "set " + var;
}
Instruction setInstruction = callFunction(getTableName(), var, args);
assertions.add(makeAssertion(setInstruction,
new VoidReturnExpectation(col, row)));
}
return assertions;
}
}
boolean isBaselineDecisionTable() {
String useFirstDataRowForEmpty = null;
useFirstDataRowForEmpty = this.getTestContext().getPageToTest().getVariable("SLIM_DT_BASELINE");
return ((useFirstDataRowForEmpty != null && !useFirstDataRowForEmpty.isEmpty())
|| baselineDecisionTable);
}
void setBaselineDecisionTable(boolean baselineDecisionTable) {
this.baselineDecisionTable = baselineDecisionTable;
}
}