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

nl.hsac.fitnesse.fixture.slim.SlimFixture Maven / Gradle / Ivy

There is a newer version: 5.3.17
Show newest version
package nl.hsac.fitnesse.fixture.slim;

import fitnesse.slim.fixtureInteraction.FixtureInteraction;
import fitnesse.slim.fixtureInteraction.InteractionAwareFixture;
import nl.hsac.fitnesse.fixture.Environment;
import nl.hsac.fitnesse.fixture.util.FileUtil;
import nl.hsac.fitnesse.slim.interaction.ExceptionHelper;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.lang3.time.StopWatch;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.File;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.function.Supplier;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * Base class for Slim fixtures.
 */
public class SlimFixture implements InteractionAwareFixture {
    public static final Pattern REGEX_EXPECTED_VALUE_PATTERN = Pattern.compile("\\s*=~/(.*)/");

    protected final Logger logger;
    private Environment environment = Environment.getInstance();
    private int repeatInterval = 100;
    private int repeatMaxCount = 30_000;
    private StopWatch repeatTimer = new StopWatch();
    private int repeatCount = 0;
    private long repeatTime = 0;
    protected final String filesDir = getEnvironment().getFitNesseFilesSectionDir();

    public SlimFixture() {
        logger = LoggerFactory.getLogger(getClass());
    }

    @Override
    public Object aroundSlimInvoke(FixtureInteraction interaction, Method method, Object... arguments)
            throws InvocationTargetException, IllegalAccessException {
        Object result;
        try {
            beforeInvoke(method, arguments);
            result = invoke(interaction, method, arguments);
        } catch (Throwable t) {
            Throwable realEx = ExceptionHelper.stripReflectionException(t);
            Throwable toThrow = handleException(method, arguments, realEx);
            if (toThrow instanceof RuntimeException) {
                throw (RuntimeException) toThrow;
            } else if (toThrow instanceof Error) {
                throw (Error) toThrow;
            }
            throw ExceptionHelper.wrapInReflectionException(toThrow);
        }
        result = afterCompletion(method, arguments, result);
        return result;
    }

    protected void beforeInvoke(Method method, Object[] arguments) {
    }

    protected Object invoke(FixtureInteraction interaction, Method method, Object[] arguments)
            throws Throwable {
        return interaction.methodInvoke(method, this, arguments);
    }

    protected Throwable handleException(Method method, Object[] arguments, Throwable t) {
        // convert any Fit, non-stacktrace, exception to our Slim equivalent
        if (t instanceof fit.exception.FitFailureException) {
            String m = t.getMessage();
            t = new SlimFixtureException(false, "
" + m + "
"); } return t; } protected Object afterCompletion(Method method, Object[] arguments, Object result) { return result; } /** * @return environment to be used. */ protected Environment getEnvironment() { return environment; } protected String getUrl(String htmlLink) { return getEnvironment().getHtmlCleaner().getUrl(htmlLink); } /** * Stores a (global) value so it can be accessed by other fixtures/pages. * @param symbolName name to store value under. * @param value value to store. */ public void setGlobalValueTo(String symbolName, String value) { getEnvironment().setSymbol(symbolName, value); } /** * Retrieves a (global) value, which was previously stored using #setGlobalValueTo(). * @param symbolName name value was stored under. */ public String globalValue(String symbolName) { return getEnvironment().getSymbol(symbolName); } /** * Removes result of wiki formatting (for e.g. email addresses) if needed. * @param rawValue value as received from FitNesse. * @return rawValue if it was just text, cleaned version if it was not. */ protected T cleanupValue(T rawValue) { return getEnvironment().getHtmlCleaner().cleanupValue(rawValue); } public boolean waitSeconds(int i) { return waitMilliseconds(i * 1000); } public boolean waitMilliseconds(int i) { boolean result; try { Thread.sleep(i); result = true; } catch (InterruptedException e) { result = false; } return result; } // Polling public void setRepeatIntervalToMilliseconds(int milliseconds) { repeatInterval = milliseconds; } public long repeatInterval() { return repeatInterval; } public void repeatAtMostTimes(int maxCount) { repeatMaxCount = maxCount; } public int repeatAtMostTimes() { return repeatMaxCount; } public int repeatCount() { return repeatCount; } public long timeSpentRepeating() { return repeatTime; } protected boolean repeatUntil(RepeatCompletion repeat) { repeatTime = 0; repeatTimer.start(); StopWatch loopTimer = new StopWatch(); loopTimer.start(); boolean result = false; try { try { result = repeat.isFinished(); } catch (RuntimeException e) { logger.warn("Error while checking we can stop repeating before starting loop", e); } for (repeatCount = 0; !result && repeatCount < repeatMaxCount; repeatCount++) { int nextInterval = getNextInterval(loopTimer); waitMilliseconds(nextInterval); loopTimer.start(); repeat.repeat(); try { result = repeat.isFinished(); } catch (RuntimeException e) { logger.warn("Error while checking whether we can stop repeating, loop count {} of {}", repeatCount, repeatMaxCount, e); } } } finally { repeatTime = repeatTimer.getTime(); repeatTimer.reset(); } return result; } private int getNextInterval(StopWatch loopTimer) { int nextInterval; long loopTime = loopTimer.getTime(); nextInterval = Math.max(0, ((int) (repeatInterval - loopTime))); loopTimer.reset(); return nextInterval; } protected boolean repeatUntilNot(RepeatCompletion repeat) { return repeatUntil(new Negate(repeat)); } protected boolean compareActualToExpected(Object expected, Object actual) { boolean result; if (expected == null) { result = actual == null; } else if (actual == null) { result = expected.equals("null"); } else if (expected.equals(actual)) { result = true; } else { String expectedStr = expected.toString(); String actualStr = actual.toString(); result = expectedStr.equals(actualStr) || regexMatch(expectedStr, actualStr); } return result; } protected boolean regexMatch(String expected, String actual) { boolean result = false; Matcher matcher = REGEX_EXPECTED_VALUE_PATTERN.matcher(expected); if (matcher.matches()) { String regex = matcher.group(1); result = actual.matches(regex); } return result; } /** * Interface to repeat a call until a condition is met. */ public interface RepeatCompletion { /** * @return true if no more repeats are needed. */ boolean isFinished(); /** * Performs the action again. */ void repeat(); } /** * RepeatCompletion which negates the completion condition of another completion, but performs same action. */ public class Negate implements RepeatCompletion { private final RepeatCompletion nested; /** * Creates new with same action, but the exact opposite completion condition. * @param nested completion whose #isFinished() will be negated. */ public Negate(RepeatCompletion nested) { this.nested = nested; } @Override public boolean isFinished() { return !nested.isFinished(); } @Override public void repeat() { nested.repeat(); } } /** * RepeatCompletion using optional Runnable in repeat, calls function to determine whether it is completed. */ public static class FunctionalCompletion implements RepeatCompletion { private Supplier isFinishedSupplier; private Runnable repeater; public FunctionalCompletion() { } public FunctionalCompletion(Supplier isFinishedSupplier) { this(isFinishedSupplier, null); } public FunctionalCompletion(Supplier isFinishedSupplier, Runnable repeater) { setIsFinishedSupplier(isFinishedSupplier); setRepeater(repeater); } @Override public boolean isFinished() { return Boolean.TRUE.equals(isFinishedSupplier.get()); } @Override public void repeat() { if (repeater != null) { repeater.run(); } } public void setIsFinishedSupplier(Supplier isFinishedSupplier) { this.isFinishedSupplier = isFinishedSupplier; } public void setRepeater(Runnable repeater) { this.repeater = repeater; } } // Polling /** * Creates a file using the supplied content. * @param dir directory to create file in. * @param fileName name for file. * @param content content to save. * @return link to created file. */ protected String createFile(String dir, String fileName, byte[] content) { String baseName = FilenameUtils.getBaseName(fileName); String ext = FilenameUtils.getExtension(fileName); String downloadedFile = FileUtil.saveToFile(dir + baseName, ext, content); return linkToFile(downloadedFile); } /** * Converts a file path into a relative wiki path, if the path is insides the wiki's 'files' section. * @param filePath path to file. * @return relative URL pointing to the file (so a hyperlink to it can be created). */ protected String getWikiUrl(String filePath) { return getEnvironment().getWikiUrl(filePath); } /** * Creates a wiki link to a file. * @param f file. * @return link referencing the file. */ protected String linkToFile(String f) { return linkToFile(new File(f)); } /** * Creates a wiki link to a file. * @param f file. * @return link referencing the file. */ protected String linkToFile(File f) { String url = getWikiUrl(f.getAbsolutePath()); if (url == null) { url = f.toURI().toString(); } return String.format("%s", url, f.getName()); } /** * Gets absolute path from wiki url, if file exists. * @param wikiUrl a relative path that can be used in wiki page, or any file path. * @return absolute path to the target of the url, if such a file exists; null if the target does not exist. */ protected String getFilePathFromWikiUrl(String wikiUrl) { return getEnvironment().getFilePathFromWikiUrl(wikiUrl); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy