/*
* 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.htmlparser.FitTable;
import de.cologneintelligence.fitgoodies.typehandler.TypeHandler;
import de.cologneintelligence.fitgoodies.typehandler.TypeHandlerFactory;
import de.cologneintelligence.fitgoodies.util.DependencyManager;
import de.cologneintelligence.fitgoodies.util.FitUtils;
import de.cologneintelligence.fitgoodies.valuereceivers.ValueReceiver;
import de.cologneintelligence.fitgoodies.valuereceivers.ValueReceiverFactory;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
public class Fixture {
protected Map<String, String> args;
protected TypeHandlerFactory typeHandlerFactory = DependencyManager.getOrCreate(TypeHandlerFactory.class);
protected ValueReceiverFactory valueReceiverFactory = DependencyManager.getOrCreate(ValueReceiverFactory.class);
protected Validator validator = DependencyManager.getOrCreate(Validator.class);
/**
* Sets the fixture parameters.
* <p>
* Normally, these values are generated by reading the first line of the
* table. This method is primary useful for debugging. You won't need it
* otherwise.
*
* @param args parameters to store in {@code args}
*/
public final void setParams(final Map<String, String> args) {
this.args = args;
}
/**
* Looks up a given parameter in the fixture's argument list.
*
* @param paramName the parameter name to look up
* @return the parameter value, if it could be found, {@code null} otherwise
* @see #getArg(String, String) {@link #getArg(String, String)}
* @see #getArg(String, String)
* {@link #getArg(String, String)}
*/
public final String getArg(final String paramName) {
return getArg(paramName, null);
}
/**
* Finds an argument in an given argument list.
* <p>
* The search for an argument is case-insensitive and whitespaces at the
* beginning and the end are ignored. The argument's name and its value are
* separated by an equal sign. All these inputs will result in
* "world", if you look up "hello":
* <p>
* "hello=world", " hello = world ",
* "HeLLo = world".</p>
* <p>
* Note: the case of the value is unchanged.
*
* @param argName the argument name to look up
* @param defaultValue the result value if the argument does not exist
* @return the argument's value without namespaces, or defaultValue
* @see #getArgNames() getArgs
* @see #copyParamsToFixture() copyParamsToFixture
*/
public String getArg(final String argName, final String defaultValue) {
if (args == null || !args.containsKey(argName)) {
return defaultValue;
} else {
return validator.preProcess(args.get(argName));
}
}
// Traversal //////////////////////////
/**
* Initializes the fixture arguments, call {@code setUp},
* {@code fit.Fixture.doTable(Parse)} and {@code tearDown()}.
*
* @param table the table to be processed
*/
public void doTable(FitTable table) {
copyParamsToFixture();
try {
setUp();
try {
doRows(table.rows());
} catch (Exception e) {
table.exception(e);
}
tearDown();
} catch (final Exception e) {
table.exception(e);
}
table.finishExecution();
}
/**
* extracts and removes parameters from a row.
*
* @param row row to process
* @return extracted parameters
*/
protected String[] extractColumnParameters(FitRow row) {
final List<String> result = new ArrayList<>();
for (FitCell cell : row.cells()) {
result.add(FitUtils.extractCellParameter(cell));
}
return result.toArray(new String[result.size()]);
}
protected void doRows(List<FitRow> rows) throws Exception {
for (FitRow row : rows) {
doRow(row);
}
}
protected void doRow(FitRow row) throws Exception {
doCells(row.cells());
}
protected void doCells(List<FitCell> cells) {
for (int i = 0; i < cells.size(); i++) {
FitCell cell = cells.get(i);
try {
doCell(cell, i);
} catch (Exception e) {
cell.exception(e);
}
}
}
protected void doCell(FitCell cell, int columnNumber) throws Exception {
cell.ignore();
}
/**
* Does nothing. Override it to initialize the fixture.
* The method is called before doTables.
*
* @throws Exception any kind of exception aborts the execution of this fixture
*/
public void setUp() throws Exception {
}
/**
* Does nothing. Override it to tear down the fixture.
* The method is called after doTables.
*
* @throws Exception any kind of exception aborts the execution of this fixture
*/
public void tearDown() throws Exception {
}
// Parameters ///////////////////////////////
/**
* Reads the argument list and copies all values in public members
* with the same name.
* <p>
* If these members do not exist, the argument is skipped. You can still
* read the values using {@link #getArg(String, String)}.
*
* @see #getArg(String, String) getArg
*/
public void copyParamsToFixture() {
for (final String fieldName : getArgNames()) {
ValueReceiver valueReceiver;
try {
valueReceiver = valueReceiverFactory.createReceiver(this, fieldName);
} catch (NoSuchMethodException | NoSuchFieldException e) {
continue;
}
TypeHandler handler = createTypeHandler(valueReceiver, null);
String fieldValueString = getArg(fieldName, null);
try {
Object fieldValue = handler.parse(fieldValueString);
valueReceiver.set(this, fieldValue);
} catch (Exception ignored) {
}
}
}
/**
* Returns all argument names.
*
* @return a list of all given argument names.
* @see #getArg(String, String) getArg
* @see #copyParamsToFixture() copyParamsToFixture
*/
protected String[] getArgNames() {
if (args == null) {
return new String[]{};
}
return args.keySet().toArray(new String[args.keySet().size()]);
}
// Utility //////////////////////////////////
/**
* Replacement of {@code check} which resolves cross-references
* before calling the original check method of fit.
*
* @param cell the cell to check
* @param valueReceiver TypeAdapter to use
* @param currentCellParameter parameter of the current cell
*/
public void check(final FitCell cell, ValueReceiver valueReceiver, String currentCellParameter) {
validator.process(cell, valueReceiver, currentCellParameter, typeHandlerFactory);
}
protected TypeHandler createTypeHandler(ValueReceiver valueReceiver, String cellParameter) {
return typeHandlerFactory.getHandler(valueReceiver.getType(), cellParameter);
}
protected ValueReceiver createReceiver(Object target, String name) throws NoSuchMethodException, NoSuchFieldException {
return valueReceiverFactory.createReceiver(target, name);
}
protected ValueReceiver createReceiver(Object target, Method method) throws NoSuchMethodException, NoSuchFieldException {
return valueReceiverFactory.createReceiver(target, method);
}
}