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

fitnesse.testsystems.slim.tables.ScriptTable Maven / Gradle / Ivy

The newest version!
// 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 fitnesse.slim.converters.BooleanConverter;
import fitnesse.slim.converters.VoidConverter;
import fitnesse.slim.instructions.Instruction;
import fitnesse.testsystems.TestExecutionException;
import fitnesse.testsystems.TestResult;
import fitnesse.testsystems.slim.SlimTestContext;
import fitnesse.testsystems.slim.Table;
import fitnesse.testsystems.slim.results.SlimTestResult;
import fitnesse.util.StringUtils;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public class ScriptTable extends SlimTable {

  public ScriptTable(Table table, String tableId, SlimTestContext context) {
    super(table, tableId, context);
  }

  /**
   * Template method to provide the keyword that identifies the table type.
   *
   * @return table type
   */
  @Override
  protected String getTableType() {
    return "scriptTable";
  }

  /**
   * Template method to provide the keyword that identifies the table type.
   *
   * @return keyword for script table
   */
  protected String getTableKeyword() {
    return "script";
  }

  /**
   * Template method to provide the keyword for the {@code start} action.
   *
   * @return keyword for {@code start} action
   */
  protected String getStartKeyword() {
    return "start";
  }

  /**
   * Template method to provide the keyword for the {@code check} action.
   *
   * @return keyword for {@code check} action
   */
  protected String getCheckKeyword() {
    return "check";
  }

  /**
   * Template method to provide the keyword for the {@code checkNot} action.
   *
   * @return keyword for {@code checkNot} action
   */
  protected String getCheckNotKeyword() {
    return "check not";
  }

  /**
   * Template method to provide the keyword for the {@code reject} action.
   *
   * @return keyword for {@code reject} action
   */
  protected String getRejectKeyword() {
    return "reject";
  }

  /**
   * Template method to provide the keyword for the {@code ensure} action.
   *
   * @return keyword for {@code ensure} action
   */
  protected String getEnsureKeyword() {
    return "ensure";
  }

  /**
   * Template method to provide the keyword for the {@code show} action.
   *
   * @return keyword for {@code show} action
   */
  protected String getShowKeyword() {
    return "show";
  }

  /**
   * Template method to provide the keyword for the {@code note} action.
   *
   * @return keyword for {@code note} action
   */
  protected String getNoteKeyword() {
    return "note";
  }

  @Override
  public List getAssertions() throws TestExecutionException {
    List assertions = new ArrayList<>();
    // TODO: Should take into account here that a table can be assigned as
    if (isTopLevelTable()) {
      getTestContext().setCurrentScriptClass(getClass());
      List createAssertions = startActor();
      if (createAssertions != null) {
        assertions.addAll(createAssertions);
      }
    }
    for (int row = 1; row < table.getRowCount(); row++)
      assertions.addAll(instructionsForRow(row));
    return assertions;
  }

  private boolean isTopLevelTable() {
    return getParent() == null;
  }

  // returns a list of statements
  protected List instructionsForRow(int row) throws TestExecutionException {
    String firstCell = table.getCellContents(0, row).trim();
    List assertions;
    String match;
    if (firstCell.equalsIgnoreCase(getStartKeyword()))
      assertions = startActor(row);
    else if (firstCell.equalsIgnoreCase(getCheckKeyword()))
      assertions = checkAction(row);
    else if (firstCell.equalsIgnoreCase(getCheckNotKeyword()))
      assertions = checkNotAction(row);
    else if (firstCell.equalsIgnoreCase(getRejectKeyword()))
      assertions = reject(row);
    else if (firstCell.equalsIgnoreCase(getEnsureKeyword()))
      assertions = ensure(row);
    else if (firstCell.equalsIgnoreCase(getShowKeyword()))
      assertions = show(row);
    else if (firstCell.equalsIgnoreCase(getNoteKeyword()))
      assertions = note(row);
    else if ((match = isSymbolAssignment(0, row)) != null)
      assertions = actionAndAssign(match, row);
    else if (firstCell.isEmpty())
      assertions = note(row);
    else if (firstCell.trim().startsWith("#") || firstCell.trim().startsWith("*"))
      assertions = note(row);
    else {
      // action() is for now the only function that returns a list of statements
      assertions = action(row);
    }
    return assertions;
  }

  protected List actionAndAssign(String symbolName, int row) throws SyntaxError {
    List assertions = new ArrayList<>();
    int lastCol = table.getColumnCountInRow(row) - 1;
    String actionName = getActionNameStartingAt(1, lastCol, row);
    if (!actionName.equals("")) {
      String[] args = getArgumentsStartingAt(1 + 1, lastCol, row, assertions);
      assertions.add(makeAssertion(callAndAssign(symbolName, getTableType() + "Actor", actionName, (Object[]) args),
        new SymbolAssignmentExpectation(symbolName, 0, row)));

    }
    return assertions;
  }

  protected List action(int row) throws TestExecutionException {
    List assertions = assertionsFromScenario(row);
    if (assertions.isEmpty()) {
      // Invoke fixture:
      int lastCol = table.getColumnCountInRow(row) - 1;
      return invokeAction(0, lastCol, row, new ScriptActionExpectation(0, row));
    }
    return assertions;
  }

  protected List assertionsFromScenario(int row) throws TestExecutionException {
    int lastCol = table.getColumnCountInRow(row) - 1;
    String scenarioName = getScenarioNameFromAlternatingCells(lastCol, row);
    ScenarioTable scenario = getTestContext().getScenario(scenarioName);
    String[] args = null;
    List assertions = new ArrayList<>();
    if (scenario != null) {
      args = getArgumentsStartingAt(1, lastCol, row, assertions);
    } else if (lastCol == 0) {
      String cellContents = table.getCellContents(0, row);
      scenario = getTestContext().getScenarioByPattern(cellContents);
      if (scenario != null) {
        args = scenario.matchParameters(cellContents);
      }
    }
    if (scenario != null) {
      scenario.setCustomComparatorRegistry(customComparatorRegistry);
      assertions.addAll(scenario.call(args, this, row));
    }
    return assertions;
  }

  protected String getScenarioNameFromAlternatingCells(int endingCol, int row) throws SyntaxError {
    return RowHelper.getScenarioNameFromAlternatingCells(table, endingCol, row);
  }

  protected List note(int row) {
    return Collections.emptyList();
  }

  protected List show(int row) throws SyntaxError {
    int lastCol = table.getColumnCountInRow(row) - 1;
    return invokeAction(1, lastCol, row,
      new ShowActionExpectation(0, row));
  }

  protected List ensure(int row) throws SyntaxError {
    int lastCol = table.getColumnCountInRow(row) - 1;
    return invokeAction(1, lastCol, row,
      new EnsureActionExpectation(0, row));
  }

  protected List reject(int row) throws SyntaxError {
    int lastCol = table.getColumnCountInRow(row) - 1;
    return invokeAction(1, lastCol, row,
      new RejectActionExpectation(0, row));

  }

  protected List checkAction(int row) throws SyntaxError {
    int lastColInAction = table.getColumnCountInRow(row) - 1;
    table.getCellContents(lastColInAction, row);
    return invokeAction(1, lastColInAction - 1, row,
      new ReturnedValueExpectation(lastColInAction, row));
  }

  protected List checkNotAction(int row) throws SyntaxError {
    int lastColInAction = table.getColumnCountInRow(row) - 1;
    table.getCellContents(lastColInAction, row);
    return invokeAction(1, lastColInAction - 1, row,
      new RejectedValueExpectation(lastColInAction, row));
  }

  protected List invokeAction(int startingCol, int endingCol, int row, SlimExpectation expectation) throws SyntaxError {
    String actionName = getActionNameStartingAt(startingCol, endingCol, row);
    List assertions = new ArrayList<>();
    String[] args = getArgumentsStartingAt(startingCol + 1, endingCol, row, assertions);
    assertions.add(makeAssertion(callFunction(getTableType() + "Actor", actionName, (Object[]) args),
      expectation));
    return assertions;
  }

  protected String getActionNameStartingAt(int startingCol, int endingCol, int row) throws SyntaxError {
    return RowHelper.getActionNameStartingAt(table, startingCol, endingCol, row);
  }

  // Adds extra assertions to the "assertions" list!
  protected String[] getArgumentsStartingAt(int startingCol, int endingCol, int row, List assertions) {
    ArgumentExtractor extractor = new ArgumentExtractor(startingCol, endingCol, row);
    while (extractor.hasMoreToExtract()) {
      assertions.add(makeAssertion(Instruction.NOOP_INSTRUCTION,
        new ArgumentExpectation(extractor.argumentColumn, row)));
      extractor.extractNextArgument();
    }
    return extractor.getArguments();
  }

  protected boolean invokesSequentialArgumentProcessing(String cellContents) {
    return RowHelper.invokesSequentialArgumentProcessing(cellContents);
  }

  protected List startActor() {
    if (!StringUtils.isBlank(getFixtureName())) {
      return startActor(0, getFixtureName(), 0);
    } else if (table.getColumnCountInRow(0) > 1) {
      return startActor(0);
    }
    return null;
  }

  protected List startActor(int row) {
    int classNameColumn = 1;
    String cellContents = table.getCellContents(classNameColumn, row);
    return startActor(row, cellContents, classNameColumn);
  }

  protected List startActor(int row, String cellContents, int classNameColumn) {
    List assertions = new ArrayList<>();
    String className = Disgracer.disgraceClassName(cellContents);
    String actorName = getTableType() + "Actor";
    getTestContext().setCurrentScriptActor(actorName);
    assertions.add(constructInstance(actorName, className, classNameColumn, row));
    getArgumentsStartingAt(classNameColumn + 1, table.getColumnCountInRow(row) - 1, row, assertions);
    return assertions;
  }

  public static class RowHelper {
    private static final String SEQUENTIAL_ARGUMENT_PROCESSING_SUFFIX = ";";

    public static String getScenarioNameFromAlternatingCells(Table table, int endingCol, int row) throws SyntaxError {
      String actionName = getActionNameStartingAt(table, 0, endingCol, row);
      String simpleName = StringUtils.replace(actionName, SEQUENTIAL_ARGUMENT_PROCESSING_SUFFIX, "");
      return Disgracer.disgraceClassName(simpleName);
    }

    public static String getActionNameStartingAt(Table table, int startingCol, int endingCol, int row) throws SyntaxError {
      StringBuilder actionName = new StringBuilder();
      try {
        actionName.append(table.getCellContents(startingCol, row));
      } catch (IndexOutOfBoundsException e) {
        throw new SyntaxError("Too few columns in row " + (row + 1) + ". Expected a function in column " + (startingCol + 1) + ".");
      }
      int actionNameCol = startingCol + 2;
      while (actionNameCol <= endingCol &&
        !invokesSequentialArgumentProcessing(actionName.toString())) {
        actionName.append(" ").append(table.getCellContents(actionNameCol, row));
        actionNameCol += 2;
      }
      return actionName.toString().trim();
    }

    public static boolean invokesSequentialArgumentProcessing(String cellContents) {
      return cellContents.endsWith(SEQUENTIAL_ARGUMENT_PROCESSING_SUFFIX);
    }
  }

  class ArgumentExtractor {
    private int argumentColumn;
    private int endingCol;
    private int row;

    private List arguments = new ArrayList<>();
    private int increment = 2;
    private boolean sequentialArguments = false;

    ArgumentExtractor(int startingCol, int endingCol, int row) {
      this.argumentColumn = startingCol;
      this.endingCol = endingCol;
      this.row = row;
    }

    public boolean hasMoreToExtract() {
      return argumentColumn <= endingCol;
    }

    public void extractNextArgument() {
      arguments.add(table.getCellContents(argumentColumn, row));
      String argumentKeyword = table.getCellContents(argumentColumn - 1, row);
      boolean argumentIsSequential = invokesSequentialArgumentProcessing(argumentKeyword);
      sequentialArguments = (sequentialArguments || argumentIsSequential);
      increment = sequentialArguments ? 1 : 2;
      argumentColumn += increment;
    }

    public String[] getArguments() {
      return arguments.toArray(new String[arguments.size()]);
    }
  }

  private class ScriptActionExpectation extends RowExpectation {
    private ScriptActionExpectation(int col, int row) {
      super(col, row);
    }

    @Override
    protected SlimTestResult createEvaluationMessage(String actual, String expected) {
      if (actual == null)
        return SlimTestResult.fail("null", expected);
      else if (actual.equals(VoidConverter.VOID_TAG) || actual.equals("null"))
        return SlimTestResult.plain();
      else if (actual.equals(BooleanConverter.FALSE))
        return SlimTestResult.fail();
      else if (actual.equals(BooleanConverter.TRUE))
        return SlimTestResult.pass();
      else if (actual.equals("IGNORE_SCRIPT_TEST"))
        return SlimTestResult.countTestNotRun();
      else
        return SlimTestResult.plain();
    }
  }

  private class EnsureActionExpectation extends RowExpectation {
    public EnsureActionExpectation(int col, int row) {
      super(col, row);
    }

    @Override
    protected SlimTestResult createEvaluationMessage(String actual, String expected) {
      return (actual != null && actual.equals(BooleanConverter.TRUE)) ?
        SlimTestResult.pass() : SlimTestResult.fail();
    }
  }

  private class RejectActionExpectation extends RowExpectation {
    public RejectActionExpectation(int col, int row) {
      super(col, row);
    }

    @Override
    protected SlimTestResult createEvaluationMessage(String actual, String expected) {
      if (actual == null)
        return SlimTestResult.pass();
      else
        return actual.equals(BooleanConverter.FALSE) ? SlimTestResult.pass() : SlimTestResult.fail();
    }
  }

  private class ShowActionExpectation extends RowExpectation {
    public ShowActionExpectation(int col, int row) {
      super(col, row);
    }

    @Override
    protected SlimTestResult createEvaluationMessage(String actual, String expected) {
      try {
        table.addColumnToRow(getRow(), actual);
      } catch (Exception e) {
        return SlimTestResult.fail(actual, e.getMessage());
      }
      return SlimTestResult.plain();
    }
  }

  private class ArgumentExpectation extends RowExpectation {

    private ArgumentExpectation(int col, int row) {
      super(col, row);
    }

    @Override
    public TestResult evaluateExpectation(Object returnValue) {
      table.substitute(getCol(), getRow(), replaceSymbolsWithFullExpansion(getExpected()));
      return null;
    }

    @Override
    protected SlimTestResult createEvaluationMessage(String actual, String expected) {
      return null;
    }
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy