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

cucumber.runtime.jython.JythonBackend Maven / Gradle / Ivy

package cucumber.runtime.jython;

import cucumber.api.DataTable;
import cucumber.api.Scenario;
import cucumber.runtime.Backend;
import cucumber.runtime.CucumberException;
import cucumber.runtime.Glue;
import cucumber.runtime.UnreportedStepExecutor;
import cucumber.runtime.io.Resource;
import cucumber.runtime.io.ResourceLoader;
import cucumber.runtime.snippets.FunctionNameGenerator;
import cucumber.runtime.snippets.SnippetGenerator;
import gherkin.formatter.model.Step;
import org.python.core.Py;
import org.python.core.PyException;
import org.python.core.PyInstance;
import org.python.core.PyList;
import org.python.core.PyObject;
import org.python.core.PyString;
import org.python.util.PythonInterpreter;

import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.List;

public class JythonBackend implements Backend {
    private final SnippetGenerator snippetGenerator = new SnippetGenerator(new JythonSnippet());
    private final ResourceLoader resourceLoader;
    private final PythonInterpreter jython;
    private PyObject pyWorld;
    private Glue glue;

    public JythonBackend(ResourceLoader resourceLoader, PythonInterpreter jython) {
        this.resourceLoader = resourceLoader;
        this.jython = jython;
        jython.set("backend", this);

        for (Resource resource : resourceLoader.resources("classpath:cucumber/runtime/jython", "dsl.py")) {
            runScript(resource);
        }
    }

    public JythonBackend(ResourceLoader resourceLoader) {
        this(resourceLoader, new PythonInterpreter());
    }

    @Override
    public void loadGlue(Glue glue, List gluePaths) {
        this.glue = glue;

        for (String gluePath : gluePaths) {
            for (Resource resource : resourceLoader.resources(gluePath, ".py")) {
                runScript(resource);
            }
        }
    }

    @Override
    public void setUnreportedStepExecutor(UnreportedStepExecutor executor) {
        //Not used yet
    }

    @Override
    public void buildWorld() {
        this.pyWorld = jython.eval("World()");
    }

    private void runScript(Resource resource) {
        try {
            jython.execfile(resource.getInputStream(), resource.getAbsolutePath());
        } catch (IOException e) {
            throw new CucumberException(e);
        }
    }

    @Override
    public void disposeWorld() {
    }

    @Override
    public String getSnippet(Step step, FunctionNameGenerator functionNameGenerator) {
        return snippetGenerator.getSnippet(step, functionNameGenerator);
    }

    public void registerStepdef(PyInstance stepdef, int arity) {
        glue.addStepDefinition(new JythonStepDefinition(this, stepdef, arity));
    }

    public void addBeforeHook(PyInstance hookDefinition) {
        glue.addBeforeHook(new JythonHookDefinition(this, hookDefinition));
    }

    public void addAfterHook(PyInstance hookDefinition) {
        glue.addAfterHook(new JythonHookDefinition(this, hookDefinition));
    }

    public void executeHook(PyInstance hookDefinition, Scenario scenario) {
        try {
            // Try to pass the scenario
            hookDefinition.invoke("execute", pyWorld, Py.java2py(scenario));
        } catch (PyException e) {
            if (getStacktrace(e).contains("takes exactly 1 argument (2 given)")) {
                // The stepdef doesn't want the scenario
                hookDefinition.invoke("execute", pyWorld);
            } else {
                // Some other error. Just rethrow.
                throw e;
            }
        }
    }

    private String getStacktrace(PyException e) {
        StringWriter sw = new StringWriter();
        PrintWriter pw = new PrintWriter(sw);
        e.printStackTrace(pw);
        return sw.getBuffer().toString();
    }

    private PyObject argToPyObject(Object arg) {
        if (arg instanceof DataTable) {
            return dataTableToPyArray((DataTable) arg);
        }
        return new PyString((String) arg);
    }

    private PyObject dataTableToPyArray(DataTable table) {
        PyList pyTable = new PyList();
        for (List row : table.raw()) {
            PyList pyRow = new PyList();
            for (String cell : row) {
                pyRow.append(new PyString(cell));
            }
            pyTable.append(pyRow);
        }
        return pyTable;
    }

    public void execute(PyInstance stepdef, Object[] args) throws Throwable {

        PyObject[] pyArgs = new PyObject[args.length + 1];
        pyArgs[0] = pyWorld;
        for (int i = 0; i < args.length; i++) {
            pyArgs[i + 1] = argToPyObject(args[i]);
        }
        try {
            stepdef.invoke("execute", pyArgs);
        } catch (PyException t) {
            Object unwrapped = t.value.__tojava__(Object.class);
            if (unwrapped instanceof Throwable) {
                throw (Throwable) unwrapped;
            } else {
                throw t.getCause() == null ? t : t.getCause();
            }
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy