/*
* Copyright (c) 2002 Cunningham & Cunningham, Inc.
* Copyright (c) 2009-2015 by Jochen Wierum & Cologne Intelligence
*
* This file is part of FitGoodies.
*
* FitGoodies is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* FitGoodies is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with FitGoodies. If not, see <http://www.gnu.org/licenses/>.
*/
package de.cologneintelligence.fitgoodies;
import de.cologneintelligence.fitgoodies.htmlparser.FitCell;
import de.cologneintelligence.fitgoodies.htmlparser.FitRow;
import de.cologneintelligence.fitgoodies.typehandler.TypeHandler;
import de.cologneintelligence.fitgoodies.util.FitUtils;
import de.cologneintelligence.fitgoodies.util.WaitForResult;
import de.cologneintelligence.fitgoodies.valuereceivers.ValueReceiver;
import java.lang.reflect.Method;
import java.text.ParseException;
import java.util.List;
public class ActionFixture extends Fixture {
public static final long DEFAULT_SLEEP_TIME = 100;
protected final WaitForResult waitForResult;
protected FitRow row;
protected Object actor;
private String currentCellParameter;
public ActionFixture(WaitForResult waitForResult) {
this.waitForResult = waitForResult;
this.actor = this;
}
public ActionFixture() {
this(new WaitForResult());
}
// Traversal ////////////////////////////////
@Override
protected void doRow(FitRow row) throws Exception {
currentCellParameter = FitUtils.extractCellParameter(row.cells().get(0));
this.row = row;
super.doRow(row);
}
protected void doCells(List<FitCell> cells) {
try {
Method action = getClass().getMethod(cells.get(0).getFitValue());
action.invoke(this);
} catch (Exception e) {
cells.get(0).exception(e);
}
}
// Actions //////////////////////////////////
public void start() throws Exception {
actor = Class.forName(row.cells().get(1).getFitValue()).newInstance();
}
public void enter() throws Exception {
Method method = method(1);
String cellText = row.cells().get(2).getFitValue();
method.invoke(actor, parse(method.getParameterTypes()[0], cellText));
}
private <T> T parse(Class<?> type, String cellText) throws java.text.ParseException {
String preprocessedText = validator.preProcess(cellText);
TypeHandler th = getTypeHandler(type, currentCellParameter);
@SuppressWarnings("unchecked")
T result = (T) th.parse(preprocessedText);
return result;
}
public void press() throws Exception {
method(0).invoke(actor);
}
public void check() throws Exception {
ValueReceiver receiver = createReceiver(actor, method(0));
check(row.cells().get(2), receiver, null);
}
// Utility //////////////////////////////////
protected Method method(int args) throws NoSuchMethodException {
return method(FitUtils.camel(row.cells().get(1).getFitValue()), args);
}
protected Method method(String name, int args) throws NoSuchMethodException {
Method methods[] = actor.getClass().getMethods();
Method result = null;
for (Method m : methods) {
if (m.getName().equals(name) && m.getParameterTypes().length == args) {
if (result == null) {
result = m;
} else {
throw new NoSuchMethodException("too many implementations");
}
}
}
if (result == null) {
throw new NoSuchMethodException(name);
}
return result;
}
/**
* Waits until a method returns true. The command takes a method name
* without parameters and a return value of {@code Boolean} as the first
* parameter and a timeout in ms as the second parameter.<br>
* The method is called every {@code sleepTime}ms, until it returns true or the timeout is
* exceeded.
*
* @throws ParseException when the cell cannot be parsed.
* @throws NoSuchMethodException when the specified method does not exist.
*/
public void waitFor() throws ParseException, NoSuchMethodException {
Method method = method(0);
long maxTime = parse(Long.class, row.cells().get(2).getFitValue());
long sleepTime = getSleepTime();
waitForResult.wait(actor, method, maxTime, sleepTime);
writeResultIntoCell(waitForResult);
}
private long getSleepTime() throws ParseException {
long sleepTime = DEFAULT_SLEEP_TIME;
if (row.size() > 3) {
sleepTime = parse(Long.class, row.cells().get(3).getFitValue());
}
return sleepTime;
}
private void writeResultIntoCell(final WaitForResult waitForResult) {
FitCell cell = row.cells().get(2);
cell.setDisplayValue(Long.toString(waitForResult.getLastElapsedTime()));
if (waitForResult.lastCallWasSuccessful()) {
cell.right();
} else {
cell.wrong();
cell.info("(Timeout)");
}
}
private TypeHandler getTypeHandler(final Class<?> type, String currentCellParameter) {
return typeHandlerFactory.getHandler(type, currentCellParameter);
}
/**
* Transforms the selected row into an "enter" command and
* reinterprets it.
* <p>
* Example:
* Row content: {@code setEncoding | utf-8} <br>
* Code in the fixture:
* {@code
* public void setEncoding() throws Exception {
* transformAndEnter();
* }
* }
* <p>
* {@code
* public void setEncoding(String encoding) {
* // do stuff with encoding here
* }
* }
*
* @throws Exception should be propagated to fit.
*/
protected final void transformAndEnter() throws Exception {
FitCell cell = row.insert(0);
cell.setFitValue("enter");
Object oldActor = actor;
actor = this;
enter();
actor = oldActor;
row.remove(0);
}
}