// 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.TestSummary; import fitnesse.responders.run.slimResponder.SlimTestContext; import fitnesse.slim.SlimError; import util.StringUtil; import java.util.*; import java.util.regex.Matcher; import java.util.regex.Pattern; public class ScenarioTable extends SlimTable { private static final String instancePrefix = "scenarioTable"; private static final String underscorePattern = "\\W_(?:\\W|$)"; private String name; private List<String> inputs = new ArrayList<String>(); private Set<String> outputs = new HashSet<String>(); private final int colsInHeader = table.getColumnCountInRow(0); private boolean parameterized = false; public ScenarioTable(Table table, String tableId, SlimTestContext testContext) { super(table, tableId, testContext); } protected String getTableType() { return instancePrefix; } public void appendInstructions() { parseTable(); } private void parseTable() { validateHeader(); String firstNameCell = table.getCellContents(1, 0); parameterized = isNameParameterized(firstNameCell); name = getScenarioName(); getTestContext().addScenario(name, this); getScenarioArguments(); } private void getScenarioArguments() { if (parameterized) { getArgumentsForParameterizedName(); } else { getArgumentsForAlternatingName(); } } private void getArgumentsForAlternatingName() { for (int inputCol = 2; inputCol < colsInHeader; inputCol += 2) { String argName = table.getCellContents(inputCol, 0); if (argName.endsWith("?")) { String disgracedArgName = Disgracer.disgraceMethodName(argName.substring( 0, argName.length())); outputs.add(disgracedArgName); } else { String disgracedArgName = Disgracer.disgraceMethodName(argName); inputs.add(disgracedArgName); } } } private void getArgumentsForParameterizedName() { String argumentString = table.getCellContents(2, 0); String[] arguments = argumentString.split(","); for (String argument : arguments) { inputs.add(Disgracer.disgraceMethodName(argument.trim())); } } private String getScenarioName() { if (parameterized) { String parameterizedName = table.getCellContents(1, 0); return unparameterize(parameterizedName); } else { return getNameFromAlternatingCells(); } } public static boolean isNameParameterized(String firstNameCell) { Pattern regPat = Pattern.compile(underscorePattern); Matcher underscoreMatcher = regPat.matcher(firstNameCell); return underscoreMatcher.find(); } public static String unparameterize(String firstNameCell) { String name = firstNameCell.replaceAll(underscorePattern, " ").trim(); return Disgracer.disgraceClassName(name); } private String getNameFromAlternatingCells() { StringBuffer nameBuffer = new StringBuffer(); for (int nameCol = 1; nameCol < colsInHeader; nameCol += 2) nameBuffer.append(table.getCellContents(nameCol, 0)).append(" "); return Disgracer.disgraceClassName(nameBuffer.toString().trim()); } private void validateHeader() { if (colsInHeader <= 1) { throw new SyntaxError("Scenario tables must have a name."); } } public void evaluateReturnValues(Map<String, Object> returnValues) throws Exception { } public String getName() { return name; } public Set<String> getInputs() { return new HashSet<String>(inputs); } public Set<String> getOutputs() { return outputs; } public void call(Map<String, String> scenarioArguments, SlimTable parentTable, int row) { String script = getTable().toHtml(); script = replaceArgsInScriptTable(script, scenarioArguments); insertAndProcessScript(script, parentTable, row); } public void call(String[] args, ScriptTable parentTable, int row) { Map<String, String> scenarioArguments = new HashMap<String, String>(); for (int i = 0; (i < inputs.size()) && (i < args.length); i++) scenarioArguments.put(inputs.get(i), args[i]); call(scenarioArguments, parentTable, row); } private void insertAndProcessScript(String script, SlimTable parentTable, int row) { try { TableScanner ts = new HtmlTableScanner(script); ScriptTable t = new ScriptTable(ts.getTable(0), id, parentTable.getTestContext()); parentTable.addChildTable(t, row); t.appendInstructions(parentTable.instructions); parentTable.addExpectation(new ScenarioExpectation(t, row)); } catch (Exception e) { throw new SlimError(e); } } private String replaceArgsInScriptTable(String script, Map<String, String> scenarioArguments) { for (String arg : scenarioArguments.keySet()) { if (getInputs().contains(arg)) { String argument = scenarioArguments.get(arg); script = StringUtil.replaceAll(script, "@" + arg, argument); script = StringUtil.replaceAll(script, "@{" + arg + "}", argument); } else { throw new SyntaxError(String.format( "The argument %s is not an input to the scenario.", arg)); } } return script; } public boolean isParameterized() { return parameterized; } public String[] matchParameters(String invokingString) { String parameterizedName; if (parameterized) { parameterizedName = table.getCellContents(1, 0); } else if (this.inputs.size() > 0) { StringBuilder nameBuffer = new StringBuilder(); for (int nameCol = 1; nameCol < colsInHeader; nameCol += 2) nameBuffer.append(table.getCellContents(nameCol, 0)) .append(" _ "); parameterizedName = nameBuffer.toString().trim(); } else { return null; } return getArgumentsMatchingParameterizedName(parameterizedName, invokingString); } private String[] getArgumentsMatchingParameterizedName( String parameterizedName, String invokingString) { Matcher matcher = makeParameterizedNameMatcher(parameterizedName, invokingString); if (matcher.matches()) { return extractNamesFromMatcher(matcher); } else { return null; } } private Matcher makeParameterizedNameMatcher(String parameterizedName, String invokingString) { String patternString = parameterizedName.replaceAll("_", "(.*)"); Pattern pattern = Pattern.compile(patternString); Matcher matcher = pattern.matcher(invokingString); return matcher; } private String[] extractNamesFromMatcher(Matcher matcher) { String[] arguments = new String[matcher.groupCount()]; for (int i = 0; i < arguments.length; i++) { arguments[i] = matcher.group(i + 1); } return arguments; } private class ScenarioExpectation extends Expectation { private ScriptTable scriptTable; private ScenarioExpectation(ScriptTable scriptTable, int row) { super("", -1, row); // We don't care about anything but the row. this.scriptTable = scriptTable; } public void evaluateExpectation(Map<String, Object> returnValues) { TestSummary counts = scriptTable.getTestSummary(); boolean testStatus = (counts.getWrong() + counts.getExceptions()) == 0; SlimTable parent = scriptTable.getParent(); parent.getTable().setTestStatusOnRow(getRow(), testStatus); parent.getTestSummary().add(scriptTable.getTestSummary()); } protected String createEvaluationMessage(String actual, String expected) { return null; } } }