
ste.xtest.js.BugFreeJavaScript Maven / Gradle / Ivy
/*
* xTest
* Copyright (C) 2014 Stefano Fornari
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU Affero General Public License version 3 as published by
* the Free Software Foundation with the addition of the following permission
* added to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED
* WORK IN WHICH THE COPYRIGHT IS OWNED BY Stefano Fornari, Stefano Fornari
* DISCLAIMS THE WARRANTY OF NON INFRINGEMENT OF THIRD PARTY RIGHTS.
*
* This program 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 Affero General Public License
* along with this program; if not, see http://www.gnu.org/licenses or write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301 USA.
*/
package ste.xtest.js;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import javax.script.ScriptException;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.StringEscapeUtils;
import org.apache.commons.lang3.StringUtils;
import org.mozilla.javascript.Context;
import org.mozilla.javascript.Function;
import org.mozilla.javascript.Scriptable;
import org.mozilla.javascript.UniqueTag;
import ste.xtest.junit.BugFree;
/**
* Base class for junit tests for JavaSctript scripts. It provides a simple
* framework to work with engine inside JUnit. JavaScript test cases shall
* inherit from this base class and take advantage of the facility provided.
*
* It provides two useful methods to invoke a method defined in a javascript
* file:
*
* String call(String method, String... args)
: to use if the
* invoked method returns a String and has just String parameters
* Object call(String method, Object... args)
: generic version
* of the previous one. It can be used to invoke any method
*
*
* Below a simple example of usage to test method
* replaceString(String arg1, String arg2, String arg3)
defined in
* replace.js
script file.
*
* public class ReplaceTest extends JavaScriptTest {
*
* public ReplaceTest() {
* fileName = "/replace.js"
* }
*
* @Test
* public void replace() throws Throwable {
* String method = "replaceString";
* //
* // replace arg2 with arg3 in arg1
* //
* String arg1 = "this is my cat";
* String arg2 = "cat";
* String arg3 = "dog";
*
* String result = call(method, arg1, arg2, arg3);
*
* assertEquals("this is my dog", result);
* }
*
* }
*
*
*/
public abstract class BugFreeJavaScript extends BugFree {
//
// TODO: extract common base class between JavaScriptTest and BeanShellTest
//
// ---------------------------------------------------------- Protected data
/**
* The JavaScript scope scripts are executed into
*/
protected Scriptable scope;
// ------------------------------------------------------------ Constructors
/**
* Creates a new JavaScripttest
*
* @throws ScriptException if any setup script could not be loaded.
*/
public BugFreeJavaScript() throws ScriptException {
scope = null;
Context cx = Context.enter();
scope = cx.initStandardObjects();
cx.setOptimizationLevel(-1);
//
// xtest initialization
//
loadResourceScripts(
cx,
new String[] {
"/js/xtest.init.js",
"/js/env.rhino.1.2.js",
"/js/sprintf-0.0.7.min.js",
"/js/jquery-1.11.1.min.js",
"/js/xtest.setup.js",
"/js/urlsearchparams.js"
}
);
}
// ---------------------------------------------------------- Public methods
/**
* Returns an object as defined in the current script scope
*
* @param name the object name (variable, function, ...) - NOT NULL
*
* @return the corresponding object
*
* @throws IllegalArgumentException if name is null
*/
public Object get(String name) {
if (StringUtils.isBlank(name)) {
throw new IllegalArgumentException("name can not be blank");
}
Object ret = scope.get(name, scope);
if (UniqueTag.NOT_FOUND.equals(ret)) {
return null;
}
return ret;
}
/**
* Sets a variable in the current script scope with given name and value
*
* @param name the object name (variable, function, ...) - NOT BLANK
* @param value the value - MAY BE NULL
*/
public void set(final String name, Object value) {
if (StringUtils.isBlank(name)) {
throw new IllegalArgumentException("name can not be blank");
}
scope.put(name, scope, value);
}
/**
* Load the given script from the file system (first) or the class path.
*
* @param script the script file/resource name - NOT NULL
*
* @throws IllegalArgumentException if fileName is null
* @throws IOException in case of IO errors
*
*/
public void loadScript(String script) throws IOException {
if (script == null) {
throw new IllegalArgumentException("script cannot be null");
}
//
// let's try to read the script from the file system first; if an io
// exception is thrown, then we try from the classpath
//
Context cx = Context.enter();
Reader r = null;
try {
r = new FileReader(script);
} catch(FileNotFoundException x) {
InputStream is = getClass().getResourceAsStream(script);
if (is == null) {
throw x;
}
r = new InputStreamReader(is);
} finally {
if (r != null) {
cx.evaluateReader(scope, r, script, 1, null);
r.close();
}
Context.exit();
}
}
/**
* Load the given fixture. The fixture is basically an html fragment which
* will be wrapped inside a:
*
* $("body").append(... html ...);
*
* Double quotes will be escaped.
*
* @param fixture the fixture file name - NOT NULL
*
* @throws IllegalArgumentException if fixtureis null
* @throws NotFoundException if the fixture is not found
* @throws IOException in case of IO errors
*
*/
public void loadFixture(String fixture) throws IOException {
if (fixture == null) {
throw new IllegalArgumentException("fixture cannot be null");
}
String script = String.format("$(\"body\").append(\"%s\");",
StringEscapeUtils.escapeJava(
FileUtils.readFileToString(new File(fixture))
)
);
exec(script);
}
// ------------------------------------------------------- Protected methods
/**
* Exec the given function assuming it is defined in the current script
* scope
*
* @param name the function to invoke
* @param args the arguments of the method
* @return the object returned by the invoked function
*
* @throws java.lang.Throwable if an error occurs
* @throws IllegalArgumentException if name is not a function
*/
protected Object call(String name, Object... args) throws Throwable {
Object o = scope.get(name, scope);
if (!(o instanceof Function)) {
throw new IllegalArgumentException(name + " is undefined or not a function.");
}
Function f = (Function)o;
Context cx = Context.enter();
Object result = f.call(cx, scope, scope, args);
Context.exit();
return result;
}
/**
* Exec the given script assuming it is defined in the current script
* scope
*
* @param script the script to execute - NOT NULL
* @return the object returned by execution of the script
*
* @throws IllegalArgumentException if script is null
*/
protected Object exec(String script) {
if (script == null) {
throw new IllegalArgumentException("script cannot be null");
}
Context cx = Context.enter();
Object result = cx.evaluateString(scope, script, "script", 1, null);
Context.exit();
return result;
}
// --------------------------------------------------------- Private methods
private void loadResourceScripts(final Context cx, final String[] scripts)
throws ScriptException {
InputStream is = null;
try {
for (String script: scripts) {
is = BugFreeJavaScript.class.getResourceAsStream(script);
if (is == null) {
throw new FileNotFoundException(script + " not found in classpath");
}
cx.evaluateReader(scope, new InputStreamReader(is), script, 1, null);
is.close();
is = null;
}
} catch (Exception x) {
throw new ScriptException("Error initializing the javascript engine: " + x.getMessage());
} finally {
Context.exit();
if (is != null) {
try {
is.close();
} catch (Exception x) {
}
};
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy