Fixed line endings
git-svn-id: svn://10.0.0.236/trunk@212454 18797224-902f-48f8-a5cc-f745e15eee43
This commit is contained in:
@@ -1,9 +1,15 @@
|
||||
Changes since Rhino 1.6R4
|
||||
=========================
|
||||
- Added org.mozilla.javascript.PolicySecurityController as a concrete
|
||||
implementation of an org.mozilla.javascript.SecurityController and the
|
||||
preferred way of integrating with Java security architecture.
|
||||
- When no security controller is in use, generated classes and scripts run in
|
||||
the ProtectionDomain of Rhino classes.
|
||||
- Wrapped access to system properties and creation of class loaders into
|
||||
AccessController.doPrivileged() to nicely play in secured environments.
|
||||
This file version: $Id: CHANGELOG,v 1.2 2006-09-27 08:50:41 szegedia%freemail.hu Exp $
|
||||
|
||||
Changes since Rhino 1.6R4
|
||||
=========================
|
||||
- Added org.mozilla.javascript.PolicySecurityController as a concrete
|
||||
implementation of an org.mozilla.javascript.SecurityController and the
|
||||
preferred way of integrating with Java security architecture.
|
||||
- When no security controller is in use, generated classes and scripts run in
|
||||
the ProtectionDomain of Rhino classes.
|
||||
- Wrapped access to system properties and creation of class loaders into
|
||||
AccessController.doPrivileged() to nicely play in secured environments.
|
||||
- Fixed #353300: Rhino now implements the ECMA-262 mandatory
|
||||
String.localeCompare
|
||||
- Fixed #352319: Rhino threw a ClassCastException when a continuation captured
|
||||
from a catch() block was restarted.
|
||||
|
||||
@@ -1,175 +1,175 @@
|
||||
package org.mozilla.javascript;
|
||||
|
||||
import java.lang.ref.Reference;
|
||||
import java.lang.ref.SoftReference;
|
||||
import java.lang.reflect.UndeclaredThrowableException;
|
||||
import java.security.AccessController;
|
||||
import java.security.CodeSource;
|
||||
import java.security.Policy;
|
||||
import java.security.PrivilegedAction;
|
||||
import java.security.SecureClassLoader;
|
||||
import java.util.Map;
|
||||
import java.util.Random;
|
||||
import java.util.WeakHashMap;
|
||||
|
||||
import org.mozilla.classfile.ClassFileWriter;
|
||||
|
||||
/**
|
||||
* A security controller relying on Java {@link Policy} in effect. When you use
|
||||
* this security controller, your securityDomain objects must be instances of
|
||||
* {@link CodeSource} representing the location from where you load your
|
||||
* scripts. Any Java policy "grant" statements matching the URL and certificate
|
||||
* in code sources will apply to the scripts. If you specify any certificates
|
||||
* within your {@link CodeSource} objects, it is your responsibility to verify
|
||||
* (or not) that the script source files are signed in whatever
|
||||
* implementation-specific way you're using.
|
||||
* @author Attila Szegedi
|
||||
* @version $Id: PolicySecurityController.java,v 1.1 2006-09-10 12:16:46 szegedia%freemail.hu Exp $
|
||||
*/
|
||||
public class PolicySecurityController extends SecurityController
|
||||
{
|
||||
// Use weak map, so stuff related to abandoned code sources gets cleaned up
|
||||
// automatically.
|
||||
private static final Map secureCallers = new WeakHashMap();
|
||||
|
||||
private static class Loader extends SecureClassLoader
|
||||
implements GeneratedClassLoader
|
||||
{
|
||||
private final CodeSource codeSource;
|
||||
|
||||
Loader(ClassLoader parent, CodeSource codeSource)
|
||||
{
|
||||
super(parent);
|
||||
this.codeSource = codeSource;
|
||||
}
|
||||
|
||||
public Class defineClass(String name, byte[] data)
|
||||
{
|
||||
return defineClass(name, data, 0, data.length, codeSource);
|
||||
}
|
||||
|
||||
public void linkClass(Class cl)
|
||||
{
|
||||
resolveClass(cl);
|
||||
}
|
||||
}
|
||||
|
||||
public GeneratedClassLoader createClassLoader(ClassLoader parentLoader,
|
||||
Object securityDomain)
|
||||
{
|
||||
return createLoader(parentLoader, (CodeSource)securityDomain);
|
||||
}
|
||||
|
||||
private Loader createLoader(
|
||||
final ClassLoader parent, final CodeSource securityDomain)
|
||||
{
|
||||
return (Loader)AccessController.doPrivileged(
|
||||
new PrivilegedAction()
|
||||
{
|
||||
public Object run()
|
||||
{
|
||||
return new Loader(parent, securityDomain);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public Object getDynamicSecurityDomain(Object securityDomain)
|
||||
{
|
||||
// No separate notion of dynamic security domain - just return what was
|
||||
// passed in.
|
||||
return securityDomain;
|
||||
}
|
||||
|
||||
public Object callWithDomain(Object securityDomain, Context cx,
|
||||
Callable callable, Scriptable scope, Scriptable thisObj,
|
||||
Object[] args)
|
||||
{
|
||||
SecureCaller secureCaller;
|
||||
CodeSource codeSource = (CodeSource)securityDomain;
|
||||
ClassLoader appClassLoader = cx.getApplicationClassLoader();
|
||||
DomainKey key = new DomainKey(codeSource, appClassLoader);
|
||||
synchronized(secureCallers)
|
||||
{
|
||||
Reference ref = (Reference)secureCallers.get(key);
|
||||
if(ref != null)
|
||||
{
|
||||
secureCaller = (SecureCaller)ref.get();
|
||||
}
|
||||
else
|
||||
{
|
||||
secureCaller = null;
|
||||
}
|
||||
if(secureCaller == null)
|
||||
{
|
||||
Loader l = createLoader(appClassLoader, codeSource);
|
||||
String name = SecureCaller.class.getName() + "$Sub" +
|
||||
// Being a bit paranoid about name clashes - if anyone'd figure
|
||||
// out how to get to the class loader this might become a
|
||||
// concern
|
||||
Integer.toHexString(key.hashCode()) + "_" + Long.toHexString(
|
||||
new Random().nextLong());
|
||||
// Just a trivial "class ... extends SecureCaller {}"
|
||||
// class.
|
||||
ClassFileWriter cfw = new ClassFileWriter(name,
|
||||
SecureCaller.class.getName(), "<generated>");
|
||||
Class clazz = l.defineClass(name, cfw.toByteArray());
|
||||
try
|
||||
{
|
||||
secureCaller = (SecureCaller)clazz.newInstance();
|
||||
// Using a soft reference, so we don't hold strongly on the
|
||||
// code source and allow it to get cleaned up eventually.
|
||||
secureCallers.put(key, new SoftReference(secureCaller));
|
||||
}
|
||||
catch (InstantiationException e)
|
||||
{
|
||||
throw new UndeclaredThrowableException(e);
|
||||
}
|
||||
catch (IllegalAccessException e)
|
||||
{
|
||||
throw new UndeclaredThrowableException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
return secureCaller.call(callable, cx, scope, thisObj, args);
|
||||
}
|
||||
|
||||
public static class SecureCaller
|
||||
{
|
||||
public Object call(Callable callable, Context cx, Scriptable scope,
|
||||
Scriptable thisObj, Object[] args)
|
||||
{
|
||||
return callable.call(cx, scope, thisObj, args);
|
||||
}
|
||||
}
|
||||
|
||||
private static final class DomainKey
|
||||
{
|
||||
private final CodeSource codeSource;
|
||||
private final ClassLoader appClassLoader;
|
||||
|
||||
DomainKey(CodeSource codeSource, ClassLoader appClassLoader)
|
||||
{
|
||||
this.codeSource = codeSource;
|
||||
if(codeSource == null)
|
||||
{
|
||||
throw new IllegalArgumentException("codeSource == null");
|
||||
}
|
||||
this.appClassLoader = appClassLoader;
|
||||
}
|
||||
|
||||
public boolean equals(Object obj)
|
||||
{
|
||||
if(obj == null || obj.getClass() != DomainKey.class)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
DomainKey other = (DomainKey)obj;
|
||||
return codeSource.equals(other.codeSource) && appClassLoader == other.appClassLoader;
|
||||
}
|
||||
|
||||
public int hashCode()
|
||||
{
|
||||
return codeSource.hashCode() ^ System.identityHashCode(appClassLoader);
|
||||
}
|
||||
}
|
||||
}
|
||||
package org.mozilla.javascript;
|
||||
|
||||
import java.lang.ref.Reference;
|
||||
import java.lang.ref.SoftReference;
|
||||
import java.lang.reflect.UndeclaredThrowableException;
|
||||
import java.security.AccessController;
|
||||
import java.security.CodeSource;
|
||||
import java.security.Policy;
|
||||
import java.security.PrivilegedAction;
|
||||
import java.security.SecureClassLoader;
|
||||
import java.util.Map;
|
||||
import java.util.Random;
|
||||
import java.util.WeakHashMap;
|
||||
|
||||
import org.mozilla.classfile.ClassFileWriter;
|
||||
|
||||
/**
|
||||
* A security controller relying on Java {@link Policy} in effect. When you use
|
||||
* this security controller, your securityDomain objects must be instances of
|
||||
* {@link CodeSource} representing the location from where you load your
|
||||
* scripts. Any Java policy "grant" statements matching the URL and certificate
|
||||
* in code sources will apply to the scripts. If you specify any certificates
|
||||
* within your {@link CodeSource} objects, it is your responsibility to verify
|
||||
* (or not) that the script source files are signed in whatever
|
||||
* implementation-specific way you're using.
|
||||
* @author Attila Szegedi
|
||||
* @version $Id: PolicySecurityController.java,v 1.2 2006-09-27 08:51:18 szegedia%freemail.hu Exp $
|
||||
*/
|
||||
public class PolicySecurityController extends SecurityController
|
||||
{
|
||||
// Use weak map, so stuff related to abandoned code sources gets cleaned up
|
||||
// automatically.
|
||||
private static final Map secureCallers = new WeakHashMap();
|
||||
|
||||
private static class Loader extends SecureClassLoader
|
||||
implements GeneratedClassLoader
|
||||
{
|
||||
private final CodeSource codeSource;
|
||||
|
||||
Loader(ClassLoader parent, CodeSource codeSource)
|
||||
{
|
||||
super(parent);
|
||||
this.codeSource = codeSource;
|
||||
}
|
||||
|
||||
public Class defineClass(String name, byte[] data)
|
||||
{
|
||||
return defineClass(name, data, 0, data.length, codeSource);
|
||||
}
|
||||
|
||||
public void linkClass(Class cl)
|
||||
{
|
||||
resolveClass(cl);
|
||||
}
|
||||
}
|
||||
|
||||
public GeneratedClassLoader createClassLoader(ClassLoader parentLoader,
|
||||
Object securityDomain)
|
||||
{
|
||||
return createLoader(parentLoader, (CodeSource)securityDomain);
|
||||
}
|
||||
|
||||
private Loader createLoader(
|
||||
final ClassLoader parent, final CodeSource securityDomain)
|
||||
{
|
||||
return (Loader)AccessController.doPrivileged(
|
||||
new PrivilegedAction()
|
||||
{
|
||||
public Object run()
|
||||
{
|
||||
return new Loader(parent, securityDomain);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public Object getDynamicSecurityDomain(Object securityDomain)
|
||||
{
|
||||
// No separate notion of dynamic security domain - just return what was
|
||||
// passed in.
|
||||
return securityDomain;
|
||||
}
|
||||
|
||||
public Object callWithDomain(Object securityDomain, Context cx,
|
||||
Callable callable, Scriptable scope, Scriptable thisObj,
|
||||
Object[] args)
|
||||
{
|
||||
SecureCaller secureCaller;
|
||||
CodeSource codeSource = (CodeSource)securityDomain;
|
||||
ClassLoader appClassLoader = cx.getApplicationClassLoader();
|
||||
DomainKey key = new DomainKey(codeSource, appClassLoader);
|
||||
synchronized(secureCallers)
|
||||
{
|
||||
Reference ref = (Reference)secureCallers.get(key);
|
||||
if(ref != null)
|
||||
{
|
||||
secureCaller = (SecureCaller)ref.get();
|
||||
}
|
||||
else
|
||||
{
|
||||
secureCaller = null;
|
||||
}
|
||||
if(secureCaller == null)
|
||||
{
|
||||
Loader l = createLoader(appClassLoader, codeSource);
|
||||
String name = SecureCaller.class.getName() + "$Sub" +
|
||||
// Being a bit paranoid about name clashes - if anyone'd figure
|
||||
// out how to get to the class loader this might become a
|
||||
// concern
|
||||
Integer.toHexString(key.hashCode()) + "_" + Long.toHexString(
|
||||
new Random().nextLong());
|
||||
// Just a trivial "class ... extends SecureCaller {}"
|
||||
// class.
|
||||
ClassFileWriter cfw = new ClassFileWriter(name,
|
||||
SecureCaller.class.getName(), "<generated>");
|
||||
Class clazz = l.defineClass(name, cfw.toByteArray());
|
||||
try
|
||||
{
|
||||
secureCaller = (SecureCaller)clazz.newInstance();
|
||||
// Using a soft reference, so we don't hold strongly on the
|
||||
// code source and allow it to get cleaned up eventually.
|
||||
secureCallers.put(key, new SoftReference(secureCaller));
|
||||
}
|
||||
catch (InstantiationException e)
|
||||
{
|
||||
throw new UndeclaredThrowableException(e);
|
||||
}
|
||||
catch (IllegalAccessException e)
|
||||
{
|
||||
throw new UndeclaredThrowableException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
return secureCaller.call(callable, cx, scope, thisObj, args);
|
||||
}
|
||||
|
||||
public static class SecureCaller
|
||||
{
|
||||
public Object call(Callable callable, Context cx, Scriptable scope,
|
||||
Scriptable thisObj, Object[] args)
|
||||
{
|
||||
return callable.call(cx, scope, thisObj, args);
|
||||
}
|
||||
}
|
||||
|
||||
private static final class DomainKey
|
||||
{
|
||||
private final CodeSource codeSource;
|
||||
private final ClassLoader appClassLoader;
|
||||
|
||||
DomainKey(CodeSource codeSource, ClassLoader appClassLoader)
|
||||
{
|
||||
this.codeSource = codeSource;
|
||||
if(codeSource == null)
|
||||
{
|
||||
throw new IllegalArgumentException("codeSource == null");
|
||||
}
|
||||
this.appClassLoader = appClassLoader;
|
||||
}
|
||||
|
||||
public boolean equals(Object obj)
|
||||
{
|
||||
if(obj == null || obj.getClass() != DomainKey.class)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
DomainKey other = (DomainKey)obj;
|
||||
return codeSource.equals(other.codeSource) && appClassLoader == other.appClassLoader;
|
||||
}
|
||||
|
||||
public int hashCode()
|
||||
{
|
||||
return codeSource.hashCode() ^ System.identityHashCode(appClassLoader);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,78 +1,78 @@
|
||||
/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
*
|
||||
* The contents of this file are subject to the Netscape Public
|
||||
* License Version 1.1 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a copy of
|
||||
* the License at http://www.mozilla.org/NPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS
|
||||
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
|
||||
* implied. See the License for the specific language governing
|
||||
* rights and limitations under the License.
|
||||
*
|
||||
* The Original Code is Rhino code, released
|
||||
* May 6, 1999.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape
|
||||
* Communications Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1997-1999 Netscape Communications Corporation. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Norris Boyd
|
||||
* Igor Bukanov
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the
|
||||
* terms of the GNU Public License (the "GPL"), in which case the
|
||||
* provisions of the GPL are applicable instead of those above.
|
||||
* If you wish to allow use of your version of this file only
|
||||
* under the terms of the GPL and not to allow others to use your
|
||||
* version of this file under the NPL, indicate your decision by
|
||||
* deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this
|
||||
* file under either the NPL or the GPL.
|
||||
*/
|
||||
|
||||
package org.mozilla.javascript;
|
||||
|
||||
import java.security.AccessController;
|
||||
import java.security.PrivilegedAction;
|
||||
import java.security.ProtectionDomain;
|
||||
|
||||
/**
|
||||
* @author Attila Szegedi
|
||||
* @version $Id: SecurityUtilities.java,v 1.2 2006-09-06 13:35:16 szegedia%freemail.hu Exp $
|
||||
*/
|
||||
public class SecurityUtilities
|
||||
{
|
||||
/**
|
||||
* Retrieves a system property within a privileged block. Use it only when
|
||||
* the property is used from within Rhino code and is not passed out of it.
|
||||
* @param name the name of the system property
|
||||
* @return the value of the system property
|
||||
*/
|
||||
public static String getSystemProperty(final String name)
|
||||
{
|
||||
return (String)AccessController.doPrivileged(
|
||||
new PrivilegedAction()
|
||||
{
|
||||
public Object run()
|
||||
{
|
||||
return System.getProperty(name);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public static ProtectionDomain getProtectionDomain(final Class clazz)
|
||||
{
|
||||
return (ProtectionDomain)AccessController.doPrivileged(
|
||||
new PrivilegedAction()
|
||||
{
|
||||
public Object run()
|
||||
{
|
||||
return clazz.getProtectionDomain();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
*
|
||||
* The contents of this file are subject to the Netscape Public
|
||||
* License Version 1.1 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a copy of
|
||||
* the License at http://www.mozilla.org/NPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS
|
||||
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
|
||||
* implied. See the License for the specific language governing
|
||||
* rights and limitations under the License.
|
||||
*
|
||||
* The Original Code is Rhino code, released
|
||||
* May 6, 1999.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape
|
||||
* Communications Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1997-1999 Netscape Communications Corporation. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Norris Boyd
|
||||
* Igor Bukanov
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the
|
||||
* terms of the GNU Public License (the "GPL"), in which case the
|
||||
* provisions of the GPL are applicable instead of those above.
|
||||
* If you wish to allow use of your version of this file only
|
||||
* under the terms of the GPL and not to allow others to use your
|
||||
* version of this file under the NPL, indicate your decision by
|
||||
* deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this
|
||||
* file under either the NPL or the GPL.
|
||||
*/
|
||||
|
||||
package org.mozilla.javascript;
|
||||
|
||||
import java.security.AccessController;
|
||||
import java.security.PrivilegedAction;
|
||||
import java.security.ProtectionDomain;
|
||||
|
||||
/**
|
||||
* @author Attila Szegedi
|
||||
* @version $Id: SecurityUtilities.java,v 1.3 2006-09-27 08:51:18 szegedia%freemail.hu Exp $
|
||||
*/
|
||||
public class SecurityUtilities
|
||||
{
|
||||
/**
|
||||
* Retrieves a system property within a privileged block. Use it only when
|
||||
* the property is used from within Rhino code and is not passed out of it.
|
||||
* @param name the name of the system property
|
||||
* @return the value of the system property
|
||||
*/
|
||||
public static String getSystemProperty(final String name)
|
||||
{
|
||||
return (String)AccessController.doPrivileged(
|
||||
new PrivilegedAction()
|
||||
{
|
||||
public Object run()
|
||||
{
|
||||
return System.getProperty(name);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public static ProtectionDomain getProtectionDomain(final Class clazz)
|
||||
{
|
||||
return (ProtectionDomain)AccessController.doPrivileged(
|
||||
new PrivilegedAction()
|
||||
{
|
||||
public Object run()
|
||||
{
|
||||
return clazz.getProtectionDomain();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,266 +1,266 @@
|
||||
package org.mozilla.javascript;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileFilter;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.PrintStream;
|
||||
import java.net.URL;
|
||||
import java.util.Arrays;
|
||||
import java.util.Properties;
|
||||
|
||||
import junit.framework.Assert;
|
||||
import junit.framework.TestCase;
|
||||
import junit.framework.TestSuite;
|
||||
|
||||
import org.mozilla.javascript.tools.shell.Global;
|
||||
import org.mozilla.javascript.tools.shell.Main;
|
||||
import org.mozilla.javascript.tools.shell.ShellContextFactory;
|
||||
|
||||
/**
|
||||
* Executes the tests in the js/tests directory, much like jsDriver.pl does.
|
||||
* Excludes tests found in the js/tests/rhino-n.tests file.
|
||||
* @author Attila Szegedi
|
||||
* @version $Id: StandardTests.java,v 1.2 2006-08-31 10:17:48 szegedia%freemail.hu Exp $
|
||||
*/
|
||||
public class StandardTests extends TestSuite
|
||||
{
|
||||
public static TestSuite suite() throws Exception
|
||||
{
|
||||
TestSuite suite = new TestSuite("Standard JavaScript tests");
|
||||
URL url = StandardTests.class.getResource(".");
|
||||
String path = url.getFile();
|
||||
int jsIndex = path.lastIndexOf("/js");
|
||||
if(jsIndex == -1)
|
||||
{
|
||||
throw new IllegalStateException("You aren't running the tests from within the standard mozilla/js directory structure");
|
||||
}
|
||||
path = path.substring(0, jsIndex + 3).replace('/', File.separatorChar);
|
||||
File testDir = new File(path, "tests");
|
||||
if(!testDir.isDirectory())
|
||||
{
|
||||
throw new FileNotFoundException(testDir + " is not a directory");
|
||||
}
|
||||
Properties excludes = new Properties();
|
||||
InputStream in = new FileInputStream(new File(testDir, "rhino-n.tests"));
|
||||
try
|
||||
{
|
||||
excludes.load(in);
|
||||
}
|
||||
finally
|
||||
{
|
||||
in.close();
|
||||
}
|
||||
for(int i = -1; i < 2; ++i)
|
||||
{
|
||||
TestSuite optimizationLevelSuite = new TestSuite("Optimization level " + i);
|
||||
addSuites(optimizationLevelSuite, testDir, excludes, i);
|
||||
suite.addTest(optimizationLevelSuite);
|
||||
}
|
||||
return suite;
|
||||
}
|
||||
|
||||
private static void addSuites(TestSuite topLevel, File testDir, Properties excludes, int optimizationLevel)
|
||||
{
|
||||
File[] subdirs = testDir.listFiles(new DirectoryFilter());
|
||||
Arrays.sort(subdirs);
|
||||
for (int i = 0; i < subdirs.length; i++)
|
||||
{
|
||||
File subdir = subdirs[i];
|
||||
String name = subdir.getName();
|
||||
if(name.equals("CVS"))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
TestSuite testSuite = new TestSuite(name);
|
||||
addCategories(testSuite, subdir, name + "/", excludes, optimizationLevel);
|
||||
topLevel.addTest(testSuite);
|
||||
}
|
||||
}
|
||||
|
||||
private static void addCategories(TestSuite suite, File suiteDir, String prefix, Properties excludes, int optimizationLevel)
|
||||
{
|
||||
File[] subdirs = suiteDir.listFiles(new DirectoryFilter());
|
||||
Arrays.sort(subdirs);
|
||||
for (int i = 0; i < subdirs.length; i++)
|
||||
{
|
||||
File subdir = subdirs[i];
|
||||
String name = subdir.getName();
|
||||
if(name.equals("CVS"))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
TestSuite testCategory = new TestSuite(name);
|
||||
addTests(testCategory, subdir, prefix + name + "/", excludes, optimizationLevel);
|
||||
suite.addTest(testCategory);
|
||||
}
|
||||
}
|
||||
|
||||
private static void addTests(TestSuite suite, File suiteDir, String prefix, Properties excludes, int optimizationLevel)
|
||||
{
|
||||
File[] jsFiles = suiteDir.listFiles(new JsFilter());
|
||||
Arrays.sort(jsFiles);
|
||||
for (int i = 0; i < jsFiles.length; i++)
|
||||
{
|
||||
File jsFile = jsFiles[i];
|
||||
String name = jsFile.getName();
|
||||
if(name.equals("shell.js") || name.equals("browser.js") || excludes.containsKey(prefix + name))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
suite.addTest(new JsTestCase(jsFile, optimizationLevel));
|
||||
}
|
||||
}
|
||||
|
||||
private static final class JsTestCase extends TestCase
|
||||
{
|
||||
private final File jsFile;
|
||||
private final int optimizationLevel;
|
||||
|
||||
JsTestCase(File jsFile, int optimizationLevel)
|
||||
{
|
||||
super(jsFile.getName() + (optimizationLevel == 1 ? "-compiled" : "-interpreted"));
|
||||
this.jsFile = jsFile;
|
||||
this.optimizationLevel = optimizationLevel;
|
||||
}
|
||||
|
||||
public int countTestCases()
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
private static class TestState
|
||||
{
|
||||
boolean finished;
|
||||
Exception e;
|
||||
}
|
||||
|
||||
public void runBare() throws Exception
|
||||
{
|
||||
final Global global = new Global();
|
||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||
PrintStream p = new PrintStream(out);
|
||||
global.setOut(p);
|
||||
global.setErr(p);
|
||||
final ShellContextFactory shellContextFactory = new ShellContextFactory();
|
||||
shellContextFactory.setOptimizationLevel(optimizationLevel);
|
||||
final TestState testState = new TestState();
|
||||
Thread t = new Thread(new Runnable()
|
||||
{
|
||||
public void run()
|
||||
{
|
||||
try
|
||||
{
|
||||
shellContextFactory.call(new ContextAction()
|
||||
{
|
||||
public Object run(Context cx)
|
||||
{
|
||||
global.init(cx);
|
||||
runFileIfExists(cx, global, new File(jsFile.getParentFile().getParentFile(), "shell.js"));
|
||||
runFileIfExists(cx, global, new File(jsFile.getParentFile(), "shell.js"));
|
||||
runFileIfExists(cx, global, jsFile);
|
||||
return null;
|
||||
}
|
||||
});
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
synchronized(testState)
|
||||
{
|
||||
testState.e = e;
|
||||
}
|
||||
}
|
||||
synchronized(testState)
|
||||
{
|
||||
testState.finished = true;
|
||||
}
|
||||
}
|
||||
});
|
||||
t.start();
|
||||
t.join(60000);
|
||||
boolean isNegativeTest = jsFile.getName().endsWith("-n.js");
|
||||
synchronized(testState)
|
||||
{
|
||||
if(!testState.finished)
|
||||
{
|
||||
t.stop();
|
||||
Assert.fail("Timed out");
|
||||
}
|
||||
if(testState.e != null)
|
||||
{
|
||||
if(isNegativeTest)
|
||||
{
|
||||
if(testState.e instanceof EvaluatorException)
|
||||
{
|
||||
// Expected to bomb
|
||||
return;
|
||||
}
|
||||
}
|
||||
throw testState.e;
|
||||
}
|
||||
}
|
||||
if(isNegativeTest)
|
||||
{
|
||||
Assert.fail("Test was expected to produce a runtime error");
|
||||
}
|
||||
int exitCode = 0;
|
||||
int expectedExitCode = 0;
|
||||
p.flush();
|
||||
System.out.print(new String(out.toByteArray()));
|
||||
BufferedReader r = new BufferedReader(new InputStreamReader(
|
||||
new ByteArrayInputStream(out.toByteArray())));
|
||||
String failures = "";
|
||||
for(;;)
|
||||
{
|
||||
String s = r.readLine();
|
||||
if(s == null)
|
||||
{
|
||||
break;
|
||||
}
|
||||
if(s.indexOf("FAILED!") != -1)
|
||||
{
|
||||
failures += s + '\n';
|
||||
}
|
||||
int expex = s.indexOf("EXPECT EXIT ");
|
||||
if(expex != -1)
|
||||
{
|
||||
expectedExitCode = s.charAt(expex + "EXPECT EXIT ".length()) - '0';
|
||||
}
|
||||
}
|
||||
Assert.assertEquals("Unexpected exit code", expectedExitCode, exitCode);
|
||||
if(failures != "")
|
||||
{
|
||||
Assert.fail(failures);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void runFileIfExists(Context cx, Scriptable global, File f)
|
||||
{
|
||||
if(f.isFile())
|
||||
{
|
||||
Main.processFile(cx, global, f.getPath());
|
||||
}
|
||||
}
|
||||
|
||||
private static class DirectoryFilter implements FileFilter
|
||||
{
|
||||
public boolean accept(File pathname)
|
||||
{
|
||||
return pathname.isDirectory();
|
||||
}
|
||||
}
|
||||
|
||||
private static class JsFilter implements FileFilter
|
||||
{
|
||||
public boolean accept(File pathname)
|
||||
{
|
||||
return pathname.getName().endsWith(".js");
|
||||
}
|
||||
}
|
||||
}
|
||||
package org.mozilla.javascript;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileFilter;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.PrintStream;
|
||||
import java.net.URL;
|
||||
import java.util.Arrays;
|
||||
import java.util.Properties;
|
||||
|
||||
import junit.framework.Assert;
|
||||
import junit.framework.TestCase;
|
||||
import junit.framework.TestSuite;
|
||||
|
||||
import org.mozilla.javascript.tools.shell.Global;
|
||||
import org.mozilla.javascript.tools.shell.Main;
|
||||
import org.mozilla.javascript.tools.shell.ShellContextFactory;
|
||||
|
||||
/**
|
||||
* Executes the tests in the js/tests directory, much like jsDriver.pl does.
|
||||
* Excludes tests found in the js/tests/rhino-n.tests file.
|
||||
* @author Attila Szegedi
|
||||
* @version $Id: StandardTests.java,v 1.3 2006-09-27 08:52:46 szegedia%freemail.hu Exp $
|
||||
*/
|
||||
public class StandardTests extends TestSuite
|
||||
{
|
||||
public static TestSuite suite() throws Exception
|
||||
{
|
||||
TestSuite suite = new TestSuite("Standard JavaScript tests");
|
||||
URL url = StandardTests.class.getResource(".");
|
||||
String path = url.getFile();
|
||||
int jsIndex = path.lastIndexOf("/js");
|
||||
if(jsIndex == -1)
|
||||
{
|
||||
throw new IllegalStateException("You aren't running the tests from within the standard mozilla/js directory structure");
|
||||
}
|
||||
path = path.substring(0, jsIndex + 3).replace('/', File.separatorChar);
|
||||
File testDir = new File(path, "tests");
|
||||
if(!testDir.isDirectory())
|
||||
{
|
||||
throw new FileNotFoundException(testDir + " is not a directory");
|
||||
}
|
||||
Properties excludes = new Properties();
|
||||
InputStream in = new FileInputStream(new File(testDir, "rhino-n.tests"));
|
||||
try
|
||||
{
|
||||
excludes.load(in);
|
||||
}
|
||||
finally
|
||||
{
|
||||
in.close();
|
||||
}
|
||||
for(int i = -1; i < 2; ++i)
|
||||
{
|
||||
TestSuite optimizationLevelSuite = new TestSuite("Optimization level " + i);
|
||||
addSuites(optimizationLevelSuite, testDir, excludes, i);
|
||||
suite.addTest(optimizationLevelSuite);
|
||||
}
|
||||
return suite;
|
||||
}
|
||||
|
||||
private static void addSuites(TestSuite topLevel, File testDir, Properties excludes, int optimizationLevel)
|
||||
{
|
||||
File[] subdirs = testDir.listFiles(new DirectoryFilter());
|
||||
Arrays.sort(subdirs);
|
||||
for (int i = 0; i < subdirs.length; i++)
|
||||
{
|
||||
File subdir = subdirs[i];
|
||||
String name = subdir.getName();
|
||||
if(name.equals("CVS"))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
TestSuite testSuite = new TestSuite(name);
|
||||
addCategories(testSuite, subdir, name + "/", excludes, optimizationLevel);
|
||||
topLevel.addTest(testSuite);
|
||||
}
|
||||
}
|
||||
|
||||
private static void addCategories(TestSuite suite, File suiteDir, String prefix, Properties excludes, int optimizationLevel)
|
||||
{
|
||||
File[] subdirs = suiteDir.listFiles(new DirectoryFilter());
|
||||
Arrays.sort(subdirs);
|
||||
for (int i = 0; i < subdirs.length; i++)
|
||||
{
|
||||
File subdir = subdirs[i];
|
||||
String name = subdir.getName();
|
||||
if(name.equals("CVS"))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
TestSuite testCategory = new TestSuite(name);
|
||||
addTests(testCategory, subdir, prefix + name + "/", excludes, optimizationLevel);
|
||||
suite.addTest(testCategory);
|
||||
}
|
||||
}
|
||||
|
||||
private static void addTests(TestSuite suite, File suiteDir, String prefix, Properties excludes, int optimizationLevel)
|
||||
{
|
||||
File[] jsFiles = suiteDir.listFiles(new JsFilter());
|
||||
Arrays.sort(jsFiles);
|
||||
for (int i = 0; i < jsFiles.length; i++)
|
||||
{
|
||||
File jsFile = jsFiles[i];
|
||||
String name = jsFile.getName();
|
||||
if(name.equals("shell.js") || name.equals("browser.js") || excludes.containsKey(prefix + name))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
suite.addTest(new JsTestCase(jsFile, optimizationLevel));
|
||||
}
|
||||
}
|
||||
|
||||
private static final class JsTestCase extends TestCase
|
||||
{
|
||||
private final File jsFile;
|
||||
private final int optimizationLevel;
|
||||
|
||||
JsTestCase(File jsFile, int optimizationLevel)
|
||||
{
|
||||
super(jsFile.getName() + (optimizationLevel == 1 ? "-compiled" : "-interpreted"));
|
||||
this.jsFile = jsFile;
|
||||
this.optimizationLevel = optimizationLevel;
|
||||
}
|
||||
|
||||
public int countTestCases()
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
private static class TestState
|
||||
{
|
||||
boolean finished;
|
||||
Exception e;
|
||||
}
|
||||
|
||||
public void runBare() throws Exception
|
||||
{
|
||||
final Global global = new Global();
|
||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||
PrintStream p = new PrintStream(out);
|
||||
global.setOut(p);
|
||||
global.setErr(p);
|
||||
final ShellContextFactory shellContextFactory = new ShellContextFactory();
|
||||
shellContextFactory.setOptimizationLevel(optimizationLevel);
|
||||
final TestState testState = new TestState();
|
||||
Thread t = new Thread(new Runnable()
|
||||
{
|
||||
public void run()
|
||||
{
|
||||
try
|
||||
{
|
||||
shellContextFactory.call(new ContextAction()
|
||||
{
|
||||
public Object run(Context cx)
|
||||
{
|
||||
global.init(cx);
|
||||
runFileIfExists(cx, global, new File(jsFile.getParentFile().getParentFile(), "shell.js"));
|
||||
runFileIfExists(cx, global, new File(jsFile.getParentFile(), "shell.js"));
|
||||
runFileIfExists(cx, global, jsFile);
|
||||
return null;
|
||||
}
|
||||
});
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
synchronized(testState)
|
||||
{
|
||||
testState.e = e;
|
||||
}
|
||||
}
|
||||
synchronized(testState)
|
||||
{
|
||||
testState.finished = true;
|
||||
}
|
||||
}
|
||||
});
|
||||
t.start();
|
||||
t.join(60000);
|
||||
boolean isNegativeTest = jsFile.getName().endsWith("-n.js");
|
||||
synchronized(testState)
|
||||
{
|
||||
if(!testState.finished)
|
||||
{
|
||||
t.stop();
|
||||
Assert.fail("Timed out");
|
||||
}
|
||||
if(testState.e != null)
|
||||
{
|
||||
if(isNegativeTest)
|
||||
{
|
||||
if(testState.e instanceof EvaluatorException)
|
||||
{
|
||||
// Expected to bomb
|
||||
return;
|
||||
}
|
||||
}
|
||||
throw testState.e;
|
||||
}
|
||||
}
|
||||
if(isNegativeTest)
|
||||
{
|
||||
Assert.fail("Test was expected to produce a runtime error");
|
||||
}
|
||||
int exitCode = 0;
|
||||
int expectedExitCode = 0;
|
||||
p.flush();
|
||||
System.out.print(new String(out.toByteArray()));
|
||||
BufferedReader r = new BufferedReader(new InputStreamReader(
|
||||
new ByteArrayInputStream(out.toByteArray())));
|
||||
String failures = "";
|
||||
for(;;)
|
||||
{
|
||||
String s = r.readLine();
|
||||
if(s == null)
|
||||
{
|
||||
break;
|
||||
}
|
||||
if(s.indexOf("FAILED!") != -1)
|
||||
{
|
||||
failures += s + '\n';
|
||||
}
|
||||
int expex = s.indexOf("EXPECT EXIT ");
|
||||
if(expex != -1)
|
||||
{
|
||||
expectedExitCode = s.charAt(expex + "EXPECT EXIT ".length()) - '0';
|
||||
}
|
||||
}
|
||||
Assert.assertEquals("Unexpected exit code", expectedExitCode, exitCode);
|
||||
if(failures != "")
|
||||
{
|
||||
Assert.fail(failures);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void runFileIfExists(Context cx, Scriptable global, File f)
|
||||
{
|
||||
if(f.isFile())
|
||||
{
|
||||
Main.processFile(cx, global, f.getPath());
|
||||
}
|
||||
}
|
||||
|
||||
private static class DirectoryFilter implements FileFilter
|
||||
{
|
||||
public boolean accept(File pathname)
|
||||
{
|
||||
return pathname.isDirectory();
|
||||
}
|
||||
}
|
||||
|
||||
private static class JsFilter implements FileFilter
|
||||
{
|
||||
public boolean accept(File pathname)
|
||||
{
|
||||
return pathname.getName().endsWith(".js");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user