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

fit.Fixture Maven / Gradle / Ivy

There is a newer version: 20240707
Show newest version
// Modified or written by Object Mentor, Inc. for inclusion with FitNesse.
// Copyright (c) 2002 Cunningham & Cunningham, Inc.
// Released under the terms of the GNU General Public License version 2 or later.package fit;

package fit;

import java.io.PrintWriter;
import java.io.StringWriter;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.text.DateFormat;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.StringTokenizer;

import fit.exception.CouldNotParseFitFailureException;
import fit.exception.FitFailureException;
import fit.exception.FitMatcherException;

// TODO-RcM Figure out how to make me smaller.
public class Fixture {
  public Map summary = new HashMap<>();

  public Counts counts = new Counts();

  public FixtureListener listener = new NullFixtureListener();

  protected String[] args;

  private static final Map symbols = new HashMap<>();
  private static boolean forcedAbort = false;  //Semaphores

  public static void setForcedAbort(boolean state) {
    forcedAbort = state;
  }  //Semaphores

  protected Class getTargetClass() {
    return getClass();
  }

  public class RunTime {
    long start = System.currentTimeMillis();

    long elapsed = 0;

    @Override
    public String toString() {
      elapsed = System.currentTimeMillis() - start;
      if (elapsed > 600000) {
        return d(3600000) + ":" + d(600000) + d(60000) + ":" + d(10000) + d(1000);
      } else {
        return d(60000) + ":" + d(10000) + d(1000) + "." + d(100) + d(10);
      }
    }

    String d(long scale) {
      long report = elapsed / scale;
      elapsed -= report * scale;
      return Long.toString(report);
    }
  }

  // Traversal //////////////////////////

  /* Altered by Rick to dispatch on the first Fixture */

  public void doTables(Parse tables) {
    summary.put("run date", new Date());
    summary.put("run elapsed time", new RunTime());
    if (tables != null) {
      Parse heading = tables.at(0, 0, 0);
      if (heading != null) {
        try {
          Fixture fixture = getLinkedFixtureWithArgs(tables);
          fixture.listener = listener;
          fixture.interpretTables(tables);
        } catch (Throwable e) { // NOSONAR
          exception(heading, e);
          interpretFollowingTables(tables);
        }
      }
    }
    listener.tablesFinished(counts);
    ClearSymbols();
    SemaphoreFixture.ClearSemaphores(); //Semaphores:  clear all at end
  }

  public static void ClearSymbols() {
    symbols.clear();
  }

  /* Added by Rick to allow a dispatch into DoFixture */
  protected void interpretTables(Parse tables) {
    try { // Don't create the first fixture again, because creation may do something important.
      getArgsForTable(tables); // get them again for the new fixture object
      doTable(tables);
    } catch (Exception ex) {
      exception(tables.at(0, 0, 0), ex);
      listener.tableFinished(tables);
      return;
    }
    interpretFollowingTables(tables);
  }

  /* Added by Rick */
  private void interpretFollowingTables(Parse tables) {
    listener.tableFinished(tables);
    tables = tables.more;
    while (tables != null) {
      Parse heading = tables.at(0, 0, 0);

      if (forcedAbort) ignore(heading);  //Semaphores: ignore on failed lock
      else if (heading != null) {
        try {
          Fixture fixture = getLinkedFixtureWithArgs(tables);
          fixture.doTable(tables);
        } catch (Throwable e) { // NOSONAR
          exception(heading, e);
        }
      }
      listener.tableFinished(tables);
      tables = tables.more;
    }
  }

  /* Added by Rick */
  protected Fixture getLinkedFixtureWithArgs(Parse tables) throws Throwable {
    Parse header = tables.at(0, 0, 0);
    Fixture fixture = loadFixture(header.text());
    fixture.counts = counts;
    fixture.summary = summary;
    fixture.getArgsForTable(tables);
    return fixture;
  }

  public static Fixture loadFixture(String fixtureName) throws Throwable {
    return FixtureLoader.instance().disgraceThenLoad(fixtureName);
  }

  public void getArgsForTable(Parse table) {
    List argumentList = new ArrayList<>();
    Parse parameters = table.parts.parts.more;
    for (; parameters != null; parameters = parameters.more) {
      argumentList.add(Parse.unescape(parameters.body));
    }

    args = argumentList.toArray(new String[argumentList.size()]);
  }

  public void doTable(Parse table) {
    doRows(table.parts.more);
  }

  public void doRows(Parse rows) {
    while (rows != null) {
      Parse more = rows.more;
      doRow(rows);
      rows = more;
    }
  }

  public void doRow(Parse row) {
    doCells(row.parts);
  }

  public void doCells(Parse cells) {
    for (int i = 0; cells != null; i++) {
      try {
        doCell(cells, i);
      } catch (Exception e) {
        exception(cells, e);
      }
      cells = cells.more;
    }
  }

  public void doCell(Parse cell, int columnNumber) {
    ignore(cell);
  }

  // Annotation ///////////////////////////////

  public void right(Parse cell) {
    cell.addToTag(" class=\"pass\"");
    counts.right++;
  }

  public void wrong(Parse cell) {
    cell.addToTag(" class=\"fail\"");
    counts.wrong++;
  }

  public void wrong(Parse cell, String actual) {
    wrong(cell);
    cell.addToBody(label("expected") + "
" + escape(actual) + label("actual")); } public void ignore(Parse cell) { cell.addToTag(" class=\"ignore\""); counts.ignores++; } public void exception(Parse cell, Throwable exception) { while (exception.getClass().equals(InvocationTargetException.class)) { exception = ((InvocationTargetException) exception).getTargetException(); } if (isFriendlyException(exception)) { cell.addToBody("
" + label(exception.getMessage())); } else { final StringWriter buf = new StringWriter(); exception.printStackTrace(new PrintWriter(buf)); cell.addToBody("
" + (buf.toString()) + "
"); } cell.addToTag(" class=\"error\""); counts.exceptions++; } public boolean isFriendlyException(Throwable exception) { return exception instanceof FitFailureException; } // Utility ////////////////////////////////// public String counts() { return counts.toString(); } public static String label(String string) { return " " + string + ""; } public static String gray(String string) { return " " + string + ""; } public static String escape(String string) { return escape(escape(string, '&', "&"), '<', "<"); } public static String escape(String string, char from, String to) { int i = -1; while ((i = string.indexOf(from, i + 1)) >= 0) { if (i == 0) { string = to + string.substring(1); } else if (i == string.length()) { string = string.substring(0, i) + to; } else { string = string.substring(0, i) + to + string.substring(i + 1); } } return string; } public static String camel(String name) { StringBuilder b = new StringBuilder(name.length()); StringTokenizer t = new StringTokenizer(name); b.append(t.nextToken()); while (t.hasMoreTokens()) { String token = t.nextToken(); b.append(token.substring(0, 1).toUpperCase()); // replace spaces with // camelCase b.append(token.substring(1)); } return b.toString(); } public Object parse(String s, Class type) throws Exception { if (type.equals(String.class)) { if ("null".equalsIgnoreCase(s)) return null; else if ("blank".equalsIgnoreCase(s)) return ""; else return s; } else if (type.equals(Date.class)) { return DateFormat.getDateInstance(DateFormat.SHORT).parse(s); } else if (hasParseMethod(type)) { return callParseMethod(type, s); } else { throw new CouldNotParseFitFailureException(s, type.getName()); } } public void check(Parse cell, TypeAdapter a) { String text = cell.text(); if (text.equals("")) handleBlankCell(cell, a); else if (a == null) ignore(cell); else if (text.equals("error")) handleErrorInCell(a, cell); else compareCellToResult(a, cell); } private void compareCellToResult(TypeAdapter a, Parse cell) { new CellComparator().compareCellToResult(a, cell); } public void handleBlankCell(Parse cell, TypeAdapter a) { try { cell.addToBody(gray(a.toString(a.get()))); } catch (Exception e) { cell.addToBody(gray("error")); } } private void handleErrorInCell(TypeAdapter a, Parse cell) { try { Object result = a.invoke(); wrong(cell, a.toString(result)); } catch (IllegalAccessException e) { exception(cell, e); } catch (Exception e) { right(cell); } } public String[] getArgs() { return Arrays.copyOf(args, args.length); } public static void setSymbol(String name, Object value) { symbols.put(name, (value == null) ? "null" : value); } public static Object getSymbol(String name) { return symbols.get(name); } public static boolean hasSymbol(String name) { return symbols.containsKey(name); } public static boolean hasParseMethod(Class type) { try { type.getMethod("parse", new Class[] {String.class}); return true; } catch (NoSuchMethodException e) { return false; } } public static Object callParseMethod(Class type, String s) throws Exception { Method parseMethod = type.getMethod("parse", new Class[] {String.class}); Object o = parseMethod.invoke(null, new Object[] {s}); return o; } // TODO-RcM I might be moving out of here. Can you help me find a home of my // own? private class CellComparator { private Object result = null; private Object expected = null; private TypeAdapter typeAdapter; private Parse cell; private void compareCellToResult(TypeAdapter a, Parse theCell) { typeAdapter = a; cell = theCell; try { result = typeAdapter.get(); expected = parseCell(); if (expected instanceof Unparseable) tryRelationalMatch(); else compare(); } catch (Exception e) { exception(cell, e); } } private void compare() { if (typeAdapter.equals(expected, result)) { right(cell); } else { wrong(cell, typeAdapter.toString(result)); } } private Object parseCell() { try { return typeAdapter.isRegex ? cell.text() : typeAdapter.parse(cell.text()); } // Ignore parse exceptions, print non-parse exceptions, // return null so that compareCellToResult tries relational matching. catch (NumberFormatException e) { } catch (ParseException e) { } catch (Exception e) { e.printStackTrace(); } return new Unparseable(); } private void tryRelationalMatch() { Class adapterType = typeAdapter.type; FitFailureException cantParseException = new CouldNotParseFitFailureException(cell.text(), adapterType .getName()); if (result != null) { FitMatcher matcher = new FitMatcher(cell.text(), result); try { if (matcher.matches()) right(cell); else wrong(cell); cell.body = matcher.message(); } catch (FitMatcherException fme) { exception(cell, cantParseException); } catch (Exception e) { exception(cell, e); } } else { // TODO-RcM Is this always accurate? exception(cell, cantParseException); } } } private class Unparseable { } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy