From fcdaeac01ff6d28cdc6257bd16dc24f74b29c32d Mon Sep 17 00:00:00 2001 From: "szegedia%freemail.hu" Date: Wed, 27 Sep 2006 08:52:46 +0000 Subject: [PATCH] Fixed line endings git-svn-id: svn://10.0.0.236/trunk@212454 18797224-902f-48f8-a5cc-f745e15eee43 --- mozilla/js/rhino/CHANGELOG | 24 +- .../javascript/PolicySecurityController.java | 350 ++++++------ .../mozilla/javascript/SecurityUtilities.java | 156 ++--- .../org/mozilla/javascript/StandardTests.java | 532 +++++++++--------- 4 files changed, 534 insertions(+), 528 deletions(-) diff --git a/mozilla/js/rhino/CHANGELOG b/mozilla/js/rhino/CHANGELOG index cc860cd4fbc..fb95da2fc3c 100644 --- a/mozilla/js/rhino/CHANGELOG +++ b/mozilla/js/rhino/CHANGELOG @@ -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. diff --git a/mozilla/js/rhino/src/org/mozilla/javascript/PolicySecurityController.java b/mozilla/js/rhino/src/org/mozilla/javascript/PolicySecurityController.java index f10d542ba2e..5e6a7f7760a 100644 --- a/mozilla/js/rhino/src/org/mozilla/javascript/PolicySecurityController.java +++ b/mozilla/js/rhino/src/org/mozilla/javascript/PolicySecurityController.java @@ -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(), ""); - 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(), ""); + 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); + } + } +} diff --git a/mozilla/js/rhino/src/org/mozilla/javascript/SecurityUtilities.java b/mozilla/js/rhino/src/org/mozilla/javascript/SecurityUtilities.java index b874555dc85..b2fd34ee6f2 100644 --- a/mozilla/js/rhino/src/org/mozilla/javascript/SecurityUtilities.java +++ b/mozilla/js/rhino/src/org/mozilla/javascript/SecurityUtilities.java @@ -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(); + } + }); + } +} diff --git a/mozilla/js/rhino/testsrc/org/mozilla/javascript/StandardTests.java b/mozilla/js/rhino/testsrc/org/mozilla/javascript/StandardTests.java index d5f71c3abec..00bb7c98f66 100644 --- a/mozilla/js/rhino/testsrc/org/mozilla/javascript/StandardTests.java +++ b/mozilla/js/rhino/testsrc/org/mozilla/javascript/StandardTests.java @@ -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"); + } + } +}