From a1985df10fbf562d9781d483fe4d3fa0703bc2f0 Mon Sep 17 00:00:00 2001 From: "rginda%netscape.com" Date: Wed, 2 Feb 2000 00:22:23 +0000 Subject: [PATCH] initial add --- .../javascript/qa/drivers/LiveConnectDrv.java | 289 ++++++ .../javascript/qa/drivers/LiveConnectEnv.java | 206 ++++ .../javascript/qa/drivers/LiveNavDrv.java | 75 ++ .../javascript/qa/drivers/LiveNavEnv.java | 208 ++++ .../javascript/qa/drivers/MacRefDrv.java | 18 + .../javascript/qa/drivers/MacRefEnv.java | 361 +++++++ .../javascript/qa/drivers/NavDrv.java | 243 +++++ .../javascript/qa/drivers/NavEnv.java | 224 +++++ .../javascript/qa/drivers/ObservedTask.java | 158 +++ .../javascript/qa/drivers/RefDrv.java | 256 +++++ .../javascript/qa/drivers/RefEnv.java | 295 ++++++ .../javascript/qa/drivers/RhinoDrv.java | 219 +++++ .../javascript/qa/drivers/RhinoEnv.java | 257 +++++ .../javascript/qa/drivers/TestCase.java | 52 + .../javascript/qa/drivers/TestDriver.java | 907 ++++++++++++++++++ .../qa/drivers/TestEnvironment.java | 62 ++ .../javascript/qa/drivers/TestFile.java | 65 ++ .../javascript/qa/drivers/TestLog.java | 84 ++ .../javascript/qa/drivers/TestSuite.java | 47 + 19 files changed, 4026 insertions(+) create mode 100644 js/tests/src/com/netscape/javascript/qa/drivers/LiveConnectDrv.java create mode 100644 js/tests/src/com/netscape/javascript/qa/drivers/LiveConnectEnv.java create mode 100644 js/tests/src/com/netscape/javascript/qa/drivers/LiveNavDrv.java create mode 100644 js/tests/src/com/netscape/javascript/qa/drivers/LiveNavEnv.java create mode 100644 js/tests/src/com/netscape/javascript/qa/drivers/MacRefDrv.java create mode 100644 js/tests/src/com/netscape/javascript/qa/drivers/MacRefEnv.java create mode 100644 js/tests/src/com/netscape/javascript/qa/drivers/NavDrv.java create mode 100644 js/tests/src/com/netscape/javascript/qa/drivers/NavEnv.java create mode 100644 js/tests/src/com/netscape/javascript/qa/drivers/ObservedTask.java create mode 100644 js/tests/src/com/netscape/javascript/qa/drivers/RefDrv.java create mode 100644 js/tests/src/com/netscape/javascript/qa/drivers/RefEnv.java create mode 100644 js/tests/src/com/netscape/javascript/qa/drivers/RhinoDrv.java create mode 100644 js/tests/src/com/netscape/javascript/qa/drivers/RhinoEnv.java create mode 100644 js/tests/src/com/netscape/javascript/qa/drivers/TestCase.java create mode 100644 js/tests/src/com/netscape/javascript/qa/drivers/TestDriver.java create mode 100644 js/tests/src/com/netscape/javascript/qa/drivers/TestEnvironment.java create mode 100644 js/tests/src/com/netscape/javascript/qa/drivers/TestFile.java create mode 100644 js/tests/src/com/netscape/javascript/qa/drivers/TestLog.java create mode 100644 js/tests/src/com/netscape/javascript/qa/drivers/TestSuite.java diff --git a/js/tests/src/com/netscape/javascript/qa/drivers/LiveConnectDrv.java b/js/tests/src/com/netscape/javascript/qa/drivers/LiveConnectDrv.java new file mode 100644 index 00000000000..89a11d7a121 --- /dev/null +++ b/js/tests/src/com/netscape/javascript/qa/drivers/LiveConnectDrv.java @@ -0,0 +1,289 @@ +package com.netscape.javascript.qa.drivers; + +//import netscape.javascript.*; +//import org.mozilla.javascript.*; +import java.io.*; + +/** + * LiveConnectDrv is an application that drives the testing of the LiveConnect + * API test suite. This driver runs the stand-alone JavaScript engine in C. + * To run the LiveConnectTest API suite in Navigator, use XXX an as yet unwritten + * driver, which will depend on a generated HTML file to create the test applet. + * + *

+ * The application requires the following arguments: + * + * + * + * + * + * + * + * + * + *
-d + * directory in which LiveConnect test applications are located + *
-s + * list of suites to execute (optional) + *
-o + * directory in which log files will be written + *
-e + * path to the LiveConnect shell executable + *
+ * + * LiveConnectDrv checks the directory, finds the suites in that directory, + * and in each suite a list of all the class files in that suite. For each + * class file found, LiveConnectDrv creates a new LiveConnectEnv object, + * which runs the test. + * + *

+ * + * LiveConnectDrv also generates a helper file that is passed to the JavaScript + * shell. The helper file contains statements that allow the shell to run the + * test class. + * + * + * The contents of the helper file look something like this: + * + *

+ *  var OUTPUT_DIRECTORY = value of OUTPUT_DIRECTORY
+ *  TestClassName = arguments[0];
+ *  TestClass = eval( TestClassName );
+ *  testclass = new TestClass();
+ *  quit();
+ *  
+ * + *

Each test class creates JavaScript TestCase objects through LiveConnect, + * and prints results to standard output, just like the JavaScript language + * tests do. Additionally, test logs are created. + * + *

The parent test class, LiveConnectTest, contains methods from + * com.netscape.javascript.qa.drivers.TestDriver that allow it to write + * test results directly to the log files. + * + * @see com.netscape.javascript.qa.liveconnect.LiveConnectTest + * @see LiveConnectEnv + * + * @author christine@netscape.com + * + */ + +public class LiveConnectDrv extends TestDriver { + public LiveConnectDrv( String[] args ) { + super( args ); + setSuffix( ".class"); + } + public static void main ( String[] args ) { + LiveConnectDrv d = new LiveConnectDrv( args ); + d.start(); + } + public boolean processOptions() { + int length = ARGS.length; + + if (ARGS[0].startsWith("-")) { + //XXX need to verify that we at least get valid d and -h options + + for (int i=0; i < ARGS.length; i++ ) { + if ( ARGS[i].equals("-d") ) { + this.TEST_DIRECTORY = + ARGS[i].endsWith(File.separator) + ? new File( ARGS[++i] ) + : new File( ARGS[++i] + File.separator ); + + if ( ! ( this.TEST_DIRECTORY ).isDirectory() ) { + p( "error: " + + this.TEST_DIRECTORY.getAbsolutePath() + + " is not a directory." ); + return false; + } else { + continue; + } + } + if ( ARGS[i].equals("-s") ) { + FILES = new String[20] ; + for ( int j = ++i, k=0; j < ARGS.length; j++ ) { + if ( ARGS[j].startsWith("-") ){ + break; + } + FILES[k++] = ARGS[j]; + } + } + if ( ARGS[i].equals("-h") ) { + this.HELPER_FUNCTIONS = new File( ARGS[++i] ); + if ( ! (this.HELPER_FUNCTIONS ).isFile() ) { + p( "error: "+ + this.HELPER_FUNCTIONS.getAbsolutePath()+ + " file not found." ); + return false; + } + } + if ( ARGS[i].equals("-o") ) { + String odir = ARGS[++i]; + + OUTPUT_DIRECTORY = new File( + (odir.endsWith(File.separator) ? odir : + odir+File.separator)); + + OUTPUT_DIRECTORY.mkdirs(); + + if ( !OUTPUT_DIRECTORY.exists() || + !OUTPUT_DIRECTORY.isDirectory() ) + { + p( "error: "+ + OUTPUT_DIRECTORY.getAbsolutePath()+ + " could not create directory."); + return false; + } + + } + + if ( ARGS[i].equals("-p") ) { + OPT_LEVEL = Integer.parseInt( ARGS[++i] ); + } + + if ( ARGS[i].equals("-db" )) { + DEBUG_LEVEL = Integer.parseInt( ARGS[++i] ); + OPT_LEVEL = 0; + } + + if ( ARGS[i].equals("-e")) { + EXECUTABLE = ARGS[++i]; + } + } + + return true; + + } else { + switch ( ARGS.length ) { + case 0: + p( "error: specify location of JavaScript "+ + "tests" ); + return false; + case 1: + p( "error: specify location of JavaScript "+ + "HELPER_FUNCTIONS file" ); + return false; + case 2: + this.TEST_DIRECTORY = ARGS[0].endsWith(File.separator) + ? new File( ARGS[0] ) + : new File( ARGS[0] + File.separator ); + this.HELPER_FUNCTIONS = new File( ARGS[1] ); + if ( ! ( this.TEST_DIRECTORY ).isDirectory() ) { + p( "error: " + + this.TEST_DIRECTORY.getAbsolutePath() + + " is not a directory." ); + return false; + } + if ( ! (this.HELPER_FUNCTIONS ).isFile() ) { + p( "error: "+ + this.HELPER_FUNCTIONS.getAbsolutePath()+ + " file not found." ); + return false; + } + return true; + default: + p( "could not understand arguments." ); + return false; + } + } + + } + + public synchronized void executeSuite( TestSuite suite ) { + p( "LiveConnectDrv.executeSuite " + suite.name ); + TestEnvironment context; + TestFile file; + + if ( EXECUTABLE != null ) { + generateHelperFile(); + } + + for ( int i = 0; i < suite.size(); i++ ) { + synchronized ( suite ) { + file = (TestFile) suite.elementAt( i ); + + p( file.name ); + +// if ( EXECUTABLE != null ) { + context = new LiveConnectEnv( file, suite, this ); +// } else { +// context = new LiveRhinoEnv( file, suite, this ); +// } + + synchronized( context ) { + context.runTest(); + + /* + * The following two lines are used by the other test drivers, + * but are not used by LiveConnectDrv, since each + * LiveConnecTest writes its results to these log files. + */ + + // writeFileResult( file, suite, OUTPUT_DIRECTORY ); + // writeCaseResults(file, suite, OUTPUT_DIRECTORY ); + + context.close(); + context = null; + + if ( ! file.passed ) { + suite.passed = false; + } + } + } + } + writeSuiteResult( suite, OUTPUT_DIRECTORY ); + writeSuiteSummary( suite, OUTPUT_DIRECTORY ); + } + + public void generateHelperFile() { + try { + this.HELPER_FUNCTIONS = new File( OUTPUT_DIRECTORY, "helper.js" ); + + p( "HELPER FUNCTIONS FILE IS " + HELPER_FUNCTIONS ); + FileOutputStream fos = new FileOutputStream( HELPER_FUNCTIONS ); + + fos.write( ("var OUTPUT_DIRECTORY = \"" + OUTPUT_DIRECTORY + "\";").getBytes()); + fos.write( ("var OUTPUT_FILE = arguments[1];").getBytes() ); + fos.write( ("var TestClassName = arguments[0];" ).getBytes()); + fos.write( ("var TestClass = eval( TestClassName );" ).getBytes()); + fos.write( ("var testclass = new TestClass();" ).getBytes()); + fos.write( ("testclass.run();").getBytes() ); + fos.write( ("quit();" ).getBytes()); + fos.close(); + + } catch ( Exception e ) { + p( "generateHelperFile threw " + e.toString() ); + e.printStackTrace(); + } + } + + /** + * For each class file in the suite directory, create a TestFile object. + * For LiveConnect, the test class name needs to be the name of the class + * and the file path needs to be the full package name, prepended with the + * JavaScript keyword "Packages", and without the ".class" suffix. + */ + + public void getCases( TestSuite suite ) { + enablePrivileges(); + + File dir = new File ( suite.filePath ); + String[] files = dir.list(); + + // XXX hardcoded package name. need to fix this. + + String filename = "Packages.com.netscape.javascript.qa.liveconnect." + + suite.name +"."; + + for ( int i = 0; i < files.length; i++ ) { + if ( files[i].endsWith( getSuffix() )) { + TestFile item = new TestFile( files[i], + filename + (files[i].substring(0,files[i].length() - + getSuffix().length()))); + + p( item.filePath ); + suite.addElement(item); + } + } + } +} diff --git a/js/tests/src/com/netscape/javascript/qa/drivers/LiveConnectEnv.java b/js/tests/src/com/netscape/javascript/qa/drivers/LiveConnectEnv.java new file mode 100644 index 00000000000..f022a0c33a5 --- /dev/null +++ b/js/tests/src/com/netscape/javascript/qa/drivers/LiveConnectEnv.java @@ -0,0 +1,206 @@ +/* -*- Mode: java; tab-width: 8 -*- + * Copyright © 1997, 1998 Netscape Communications Corporation, + * All Rights Reserved. + */ + +package com.netscape.javascript.qa.drivers; + +import com.netscape.javascript.qa.liveconnect.LiveConnectTest; +import java.lang.*; +import java.io.*; +import java.util.Vector; + +/** + * The LiveConnect test environment. Creates a new LiveConnect enabled + * JavaScript shell, and passes it three arguments + * + *

+ *  jsshell helper.js Packages.com.netscape.javascript.qa.liveconnect.LiveConnectTestClass js00000.tmp
+ *  
+ + * where helper.js contains some statements that allow the shell to run + * the test, and js00000.tmp is the temporary file whose name is generated + * by this class, and specifies where test results should be written. + * + * Unlike the other TestEnvironments, LiveConnectEnv does not parse the test + * result. The LiveConnectEnv uses LiveConnect to get and parse the test + * result, using LiveConnect to get the JSObject that contains the testcases. + * + * The LiveConnectEnv gets File and Suite result information from a + * temporary file that the test applet writes to the output directory + * the test + * + * @see com.netscape.javascript.qa.drivers.TestEnvironment + * @see com.netscape.javascript.qa.drivers.ObservedTask + * @see com.netscape.javascript.qa.drivers.LiveConnectDrv + * @see com.netscape.javascript.qa.liveconnect.LiveConnectTest + * + * @author christine@netscape.com + */ + +public class LiveConnectEnv implements TestEnvironment { + TestFile file; + TestSuite suite; + LiveConnectDrv driver; + ObservedTask task; + String TEMP_LOG_NAME; + File helper; + + /** + * Create a new LiveConnectEnv. + */ + public LiveConnectEnv( TestFile f, TestSuite s, LiveConnectDrv d) { + this.file = f; + this.suite = s; + this.driver = d; + this.TEMP_LOG_NAME = "js" + getRandomFileName() +".tmp"; + } + + /** + * Called by the driver to execute the test program. + */ + public synchronized void runTest() { + try { + createContext(); + file.startTime = driver.getCurrentTime(); + executeTestFile(); + file.endTime = driver.getCurrentTime(); + + if (task.getExitValue() != 0) { + System.out.println( "Abmormal program termination. "+ + "Exit value: " + task.getExitValue() ); + if ( file.name.endsWith( "-n.js" )) { + file.passed = true; + } else { + file.exception = "Process exit value: " + task.getExitValue(); + suite.passed = false; + file.passed = false; + } + } + parseResult(); + + } catch ( Exception e ) { + suite.passed = false; + file.passed = false; + e.printStackTrace(); + } + } + + /** + * Instantiate a new JavaScript shell, passing the helper file and the + * name of the test class as arguments. + */ + public Object createContext() { + task = new ObservedTask( driver.EXECUTABLE + " " + + driver.HELPER_FUNCTIONS.getAbsolutePath() + " " + + file.filePath +" "+ + TEMP_LOG_NAME, + this ); + return (Object) task; + } + + /** + * Start the shell process. + */ + public Object executeTestFile() { + try { + task.exec(); + } catch ( IOException e ) { + System.err.println( e ); + file.exception = e.toString(); + } + return null; + } + + /** + * Parse the results file for this test. The which contains data in the + * following format: + *
+     *  CLASSNAME LiveConnectTest
+     *  PASSED    [true, false]
+     *  LENGTH    [number of testcases in this test]  
+     *  NO_PASSED [number of testcases that passed]
+     *  NO_FAILED [number of testcases that failed]
+     *  
+ * + * @see com.netscape.javascript.qa.liveconnect.LiveConnectTest#writeResultsToTempFile + */ + public synchronized boolean parseResult() { + String line; + BufferedReader buf = new BufferedReader(new StringReader( + new String(task.getInput()))); + try { + do { + line = buf.readLine(); + System.out.println( line ); + } while( line != null ) ; + } catch ( IOException e ) { + System.err.println( "Exception reading process output:" + + e.toString() ); + file.exception = e.toString(); + return false; + } + + Vector label = null; + Vector value = null; + + String t = null; + + try { + FileReader fr = new FileReader( + driver.OUTPUT_DIRECTORY.getAbsolutePath()+ + TEMP_LOG_NAME ); + + BufferedReader br = new BufferedReader( fr ); + String classname = br.readLine(); + boolean passed = (new Boolean(br.readLine())).booleanValue(); + int length = (new Double(br.readLine())).intValue(); + int no_passed = (new Double(br.readLine())).intValue(); + int no_failed = (new Double(br.readLine())).intValue(); + String bugnumber = br.readLine(); + + if ( ! passed ) { + this.file.passed = false; + this.suite.passed = false; + } + this.file.totalCases += length; + this.suite.totalCases += length; + this.file.casesPassed += no_passed; + this.suite.casesPassed += no_passed; + this.file.casesFailed += no_failed; + this.suite.casesFailed += no_failed; + this.file.bugnumber = bugnumber; + + } catch ( IOException e ) { + System.err.println( e ); + e.printStackTrace(); + } + return true; + } + + public String getRandomFileName() { + return (Integer.toString((new Double(Math.random()*100000)).intValue())); + } + + /** + * Delete the temp log associated with this context. + * + */ + public void close(){ + String templog = driver.OUTPUT_DIRECTORY + TEMP_LOG_NAME; + try { + File f = new File ( templog ); + if ( f.exists() ) { + f.delete(); + } + } catch ( Exception e ) { + e.printStackTrace(); + } + return; + } + + void p( String s ) { + System.out.println( s ); + } + +} diff --git a/js/tests/src/com/netscape/javascript/qa/drivers/LiveNavDrv.java b/js/tests/src/com/netscape/javascript/qa/drivers/LiveNavDrv.java new file mode 100644 index 00000000000..f18086d6966 --- /dev/null +++ b/js/tests/src/com/netscape/javascript/qa/drivers/LiveNavDrv.java @@ -0,0 +1,75 @@ +package com.netscape.javascript.qa.drivers; + +import netscape.security.PrivilegeManager; +import netscape.javascript.JSObject; + +import java.util.Vector; +import java.util.Date; +import java.io.*; +import java.applet.Applet; + +/** + * LiveNavDrv is a test driver for running the JSObject test applets in Netscape + * Navigator. + * + * The only difference between LiveNavDrv and NavDrv is that it creates a + * LiveNavEnv object (rather than a NavEnv) in which the LiveConnect tests + * are evaluated. + * + * @see NavDrv + * @see LiveNavEnv + * + * @author christine@netscape.com + */ +public class LiveNavDrv extends NavDrv { + JSObject window; + String SUFFIX; + + public LiveNavDrv() { + super(); + setSuffix(".java"); + } + + public static void main ( String[] args ) { + System.out.println( "main" ); + LiveNavDrv d = new LiveNavDrv(); + d.start(); + } + + /** + * Iterate through suites. For each file in each suite, create a + * LiveNavEnv (in this case a Navigator window) that can load and + * evaluate the test result. + * + * @see LiveNavEnv#parseResult + */ + + public synchronized void executeSuite( TestSuite suite ) { + PrivilegeManager.enablePrivilege( "UniversalFileAccess" ); + PrivilegeManager.enablePrivilege( "UniversalFileRead" ); + PrivilegeManager.enablePrivilege( "UniversalFileWrite" ); + PrivilegeManager.enablePrivilege( "UniversalPropertyRead" ); + + LiveNavEnv context; + TestFile file; + + for ( int i = 0; i < suite.size(); i++ ) { + synchronized ( suite ) { + file = (TestFile) suite.elementAt( i ); + context = new LiveNavEnv( file, suite, this ); + context.runTest(); + + writeFileResult( file, suite, OUTPUT_DIRECTORY ); + writeCaseResults(file, suite, OUTPUT_DIRECTORY ); + context.close(); + context = null; + + if ( ! file.passed ) { + suite.passed = false; + } + } + } + writeSuiteResult( suite, OUTPUT_DIRECTORY ); + writeSuiteSummary( suite, OUTPUT_DIRECTORY ); + } +} diff --git a/js/tests/src/com/netscape/javascript/qa/drivers/LiveNavEnv.java b/js/tests/src/com/netscape/javascript/qa/drivers/LiveNavEnv.java new file mode 100644 index 00000000000..299f1506403 --- /dev/null +++ b/js/tests/src/com/netscape/javascript/qa/drivers/LiveNavEnv.java @@ -0,0 +1,208 @@ +/* -*- Mode: java; tab-width: 8 -*- + * Copyright © 1997, 1998 Netscape Communications Corporation, + * All Rights Reserved. + */ + +package com.netscape.javascript.qa.drivers; + +import java.io.*; + +import java.applet.Applet; +import java.util.Vector; +import netscape.security.PrivilegeManager; +import netscape.javascript.JSObject; +import com.netscape.javascript.qa.liveconnect.LiveConnectTest; +import com.netscape.javascript.qa.liveconnect.jsobject.JSObject_001; + +/** + * TestEnvironment for running JSObject test applets in Navigator. LiveNavDrv + * uses LiveConnect to create Navigator windows in which JavaScript tests are + * opened and evaluated. + * + * @see com.netscape.javascript.qa.drivers.LiveNavDrv + * @see com.netscape.javascript.qa.drivers.NavDrv + * @see com.netscape.javascript.qa.drivers.NavEnv + * + * @author christine@netscape.com + * + */ +public class LiveNavEnv extends NavEnv { + TestFile file; + TestSuite suite; + LiveNavDrv driver; + private JSObject result; + JSObject opener; + JSObject testcases; + JSObject location; + + boolean evaluatedSuccessfully = false; + JSObject window; + + Applet applet; + + private String WINDOW_NAME; + + /** + * Construct a new LiveNavEnv. + * + * @param file TestFile whose program will be evaluated in this + * environment + * @param suite TestSuite which this TestFile belongs to + * @param driver TestDriver that is currently running + */ + public LiveNavEnv( TestFile file, TestSuite suite, LiveNavDrv driver ) { + super( file, suite, driver ); + } + + /** + * Open the current TestFile in the window by using LiveConnect to set the + * window's location.href property to a URL where the TestFile can be + * found. + * + * XXX need to generate HTML file on the fly. + */ + public Object executeTestFile() { + try { + location = (JSObject) window.getMember( "location" ); + driver.p( file.name ); + + // we need to look for the html file in the test directory. + // the name of the file is the class name + ".html" + + String classname = (file.name.substring(0, file.name.length() - + ".class".length()) + ".html" ); + + String s = driver.HTTP_PATH + classname; + + System.out.println( "trying to set browser window to " + s ); + + location.setMember( "href", s ); + evaluatedSuccessfully = waitForCompletion(); + + } catch ( Exception e ) { + driver.p( file.name + " failed with exception: " + e ); + file.exception = e.toString(); + if ( file.name.endsWith( "-n.js" ) ) { + this.file.passed = true; + evaluatedSuccessfully = true; + } else { + this.file.passed = false; + this.suite.passed = false; + evaluatedSuccessfully = false; + } + } + return null; + } + + /** + * Get a reference to the LiveConnectTest applet. Unfortunately, due + * to reasons I don't understand, we can't just get the TestFile object + * from the LiveConnectTest via LiveConnect. Attempting to cast the + * applet to LiveConnectTest fails with a java.lang.ClassCastException, + * so we continue to use the temporary file hack in Navigator. Need a + * reference to the applet so we can properly destroy it before closing + * the Navigator window. + * + * This is http://scopus/bugsplat/show_bug.cgi?id=300350, and when that's + * fixed we can ue the getAppletClass method below to directly access + * the LiveConnectTest's TestFile file object so we don't have use the + * temporary file hack. + * + */ + public Applet getApplet() { + Object document = (Object) window.getMember("document"); + Object applets = ((JSObject) document).getMember("applets"); + return (Applet) ((JSObject) applets).getSlot( 0 ); + } + + /** + * Currently does not work. + * + * @see #getApplet + */ + + public void getAppletClass(Applet applet) { + try { + driver.p( "the class of applet is " + + applet.getClass().toString() ); + + driver.p( "is it a JSObject_001? " + + (applet instanceof JSObject_001 )); + + driver.p( "is it a LiveConnectTest? " + + (applet instanceof LiveConnectTest )); + + driver.p( "is it an Applet? " + + (applet instanceof Applet )); + + driver.p( "Try to cast applet to JSObject_001" ); + + // this throws the ClassCastException + driver.p( ((JSObject_001) applet).toString() ); + + } catch ( Exception e ) { + driver.p( "parseResult threw exception: " + e ); + } + } + + /** + * Parse the results file for this test. The which contains data in the + * following format: + *
+     *  CLASSNAME [LiveConnectTest class name]
+     *  PASSED    [true, false]
+     *  LENGTH    [number of testcases in this test]  
+     *  NO_PASSED [number of testcases that passed]
+     *  NO_FAILED [number of testcases that failed]
+     *  
+ * + * @see com.netscape.javascript.qa.liveconnect.LiveConnectTest#writeResultsToTempFile + */ + public boolean parseResult() { + applet = getApplet(); + + Vector label = null; + Vector value = null; + + try { + FileReader fr = new FileReader( + driver.OUTPUT_DIRECTORY.getAbsolutePath()+ + (driver.OUTPUT_DIRECTORY.getAbsolutePath().endsWith(File.separator) + ? "" + : File.separator ) + + LiveConnectTest.TEMP_LOG_NAME); + BufferedReader br = new BufferedReader( fr ); + String classname = br.readLine(); + boolean passed = (new Boolean(br.readLine())).booleanValue(); + int length = (new Double(br.readLine())).intValue(); + int no_passed = (new Double(br.readLine())).intValue(); + int no_failed = (new Double(br.readLine())).intValue(); + if ( ! passed ) { + this.file.passed = false; + this.suite.passed = false; + } + this.file.totalCases += length; + + this.file.casesPassed += no_passed; + this.suite.casesPassed += no_passed; + + this.file.casesFailed += no_failed; + this.suite.casesFailed += no_failed; + + } catch ( IOException e ) { + driver.p( e.toString() ); + return false; + } + return true; + } + + /** + * Destroy the test applet, close Navigator window, and delete the + * reference to the test applet's window. + */ + public void close() { + applet.destroy(); + opener.eval( WINDOW_NAME +".close()" ); + opener.eval( "delete " + WINDOW_NAME ); + } +} diff --git a/js/tests/src/com/netscape/javascript/qa/drivers/MacRefDrv.java b/js/tests/src/com/netscape/javascript/qa/drivers/MacRefDrv.java new file mode 100644 index 00000000000..bcf8351894c --- /dev/null +++ b/js/tests/src/com/netscape/javascript/qa/drivers/MacRefDrv.java @@ -0,0 +1,18 @@ +/* -*- Mode: java; tab-width: 8 -*- + * Copyright © 1997, 1998 Netscape Communications Corporation, + * All Rights Reserved. + */ + +package com.netscape.javascript.qa.drivers; + +import java.util.Vector; +import java.util.Date; +import java.io.*; +import java.applet.Applet; + + +/** + * Test driver for running the JavaScript language tests on the Macintosh. + * + * + */ \ No newline at end of file diff --git a/js/tests/src/com/netscape/javascript/qa/drivers/MacRefEnv.java b/js/tests/src/com/netscape/javascript/qa/drivers/MacRefEnv.java new file mode 100644 index 00000000000..284b357feb5 --- /dev/null +++ b/js/tests/src/com/netscape/javascript/qa/drivers/MacRefEnv.java @@ -0,0 +1,361 @@ +/* -*- Mode: java; tab-width: 8 -*- + * Copyright © 1997, 1998 Netscape Communications Corporation, + * All Rights Reserved. + */ + +package com.netscape.javascript.qa.drivers; + +import java.util.Vector; +import java.util.Date; +import java.io.*; +import java.applet.Applet; + +/** + * Test environment for running the JavaScript language tests on the Macintosh. + * On the Macintosh, we have to use JBindery, a MRJ tool, to run the tests. + * + *

+ * + * In order to get tests to run on the Mac, the shell must be built with + * MAC_TEST_HACK defined. When MAC_TEST_HACK is defined, the shell expects + * to find file called "testargs.txt" in the directory where the shell + * executable is. The shell expects testargs.txt to have one argument per line. + * Legal arguments in testargs.txt are the same as the command line arguments + * to the shell (although we only use the -f argument, which tells the shell + * to evaluate files). + * + *

+ * + * The shell writes any output generated by the print statement to a file + * called "results.txt". The test environment parses the results.txt file + * in the same way that RefEnv parses the output stream of the JavaScript + * shell process. + * + *

+ */ + +public class MacRefEnv implements TestEnvironment { + TestFile file; + TestSuite suite; + RefDrv driver; + String directoryName; + TestLog testargs; + File results; + Process task; + + /** + * Create a new MacRefEnv + * + */ + + public MacRefEnv ( TestFile f, TestSuite s, RefDrv d ) { + this.file = f; + this.suite = s; + this.driver = d; + } + + /** + * This implementation does nothing, since creating the JS shell + * automatically runs the test on the Mac. + * + */ + public Object executeTestFile() { + return null; + } + + /** + * Instantiate a new JavaScript shell which has been built with + * MAC_TEST_HACK defined. + */ + public Object createContext() { + try { + // look for a file called flagfile.flg + File flag = new File ( "flagfile.flg" ); + + if ( flag.exists() ) { + flag.delete(); + } + + task = Runtime.getRuntime().exec(driver.EXECUTABLE); + + // wait a maximum of five minutes + + int i = 0; + + while ( (! flag.exists()) && i++ <= 60 ) { + Thread.currentThread().sleep(5000); + } + + } catch (IOException x) { + System.out.println("IOException in RunJS : " + x); + } catch (InterruptedException x) { + System.out.println("InterruptedException in RunJS : " + x); + } + + return null; + } + + public boolean setupMacFiles() { + + boolean result1 = getDirectoryName(); + deleteResultsFile(); + boolean result3 = createTestargsFile(); + boolean result4 = writeTestargsFile(); + + + if ( result1 && result3 && result4 ) { + return true; + } else { + return false; + } + } + + public synchronized void runTest() { + try { + if ( setupMacFiles() ) { + file.startTime = driver.getCurrentTime(); + createContext(); + file.endTime = driver.getCurrentTime(); + } +/* + if (task.getExitValue() != 0) { + if ( file.name.endsWith( "-n.js" )) { + file.passed = true; + } else { + suite.passed = false; + file.passed = false; + } + } +*/ + if ( ! parseResult() ) { + if ( file.name.endsWith( "-n.js" ) ) { + file.passed = true; + } else { + suite.passed = false; + file.passed = false; + } +// file.exception = new String(task.getError()); + } + + } catch ( Exception e ) { + suite.passed = false; + file.passed = false; + file.exception = "Unknown process exception."; +/* + file.exception = new String(task.getError()) + + " exit value: " + task.getExitValue() + + "\nThrew Exception:" + e; +*/ + } + } + + public boolean parseResult() { + String line; + int i, j; + + results = new File( "results.txt"); + + if (! results.exists()) { + return false; + } + + // spit out all the lines we find in the result file + try { + FileReader fr = new FileReader(results); + LineNumberReader lnr = new LineNumberReader(fr); + do { + line = lnr.readLine(); + driver.p( line ); + if (line == null) { + driver.p("\tERROR: No lines to read"); + return false; + } + } while (!line.equals(sizeTag)); + + if ((line = lnr.readLine()) == null) { + return false; + } + + file.totalCases = Integer.valueOf(line).intValue(); + + if ((line = lnr.readLine()) == null) { + driver.p("\tERROR: No lines after " + sizeTag); + return false; + } + + for ( i = 0; i < file.totalCases; i++) { + String values[] = new String[tags.length]; + try { + for ( j = 0; j < tags.length; j++) { + values[j] = null; + + if (!line.startsWith(tags[j])) { + driver.p("line didn't start with " + tags[j] +":"+line); + return false; + } + while (((line = lnr.readLine()) != null) && + (!(line.startsWith(startTag)))) + { + values[j] = (values[j] == null) ? line : (values[j] + + "\n" + line); + } + if (values[j] == null) values[j] = ""; + } + if ((line == null) && (i < file.totalCases - 1)) { + driver.p("line == null and " + i + "<" + + (file.totalCases - 1)); + return false; + } + } catch ( IOException e ) { + driver.p( "Exception reading process output: " + e ); + file.exception = e.toString(); + return false; + } + + TestCase rt = new TestCase(values[0],values[1],values[4],values[2], + values[3],values[5]); + + file.bugnumber = values[6]; + file.caseVector.addElement( rt ); + + if ( rt.passed.equals("false") ) { + if ( file.name.endsWith( "-n.js" ) ) { + this.file.passed = true; + } else { + this.file.passed = false; + this.suite.passed = false; + } + } + } + try { + lnr.close(); + fr.close(); + } catch (IOException x) { + System.out.println("IOException in RunJS : " + x); + return false; + } + + + } catch (NumberFormatException nfe) { + System.out.println("\tERROR: No integer after " + sizeTag); + return false; + } catch ( IOException e ) { + System.out.println( "Exception reading process output:" + e.toString() ); + file.exception = e.toString(); + return false; + } + + return true; + } + + /** + * Get the executable's directory, which is where we will write testargs.txt + * and from where we will get results.txt. + */ + + public boolean getDirectoryName() { + directoryName = ":"; + return true; + } + + /** + * Called by the driver to execute the test program. + * + */ + + /** + * Check to see whether testargs.txt exists. If so, delete it. + */ + public boolean createTestargsFile() { + String testargsname = "testargs.txt"; + + File testargsfile = new File( testargsname ); + if ( testargsfile.exists() ) { + testargsfile.delete(); + } + + testargs = new TestLog( "testargs.txt", "" ); + + return true; + } + + public boolean deleteResultsFile() { + String resultsname = "results.txt"; + + File resultsfile = new File( resultsname ); + if ( resultsfile.exists() ) { + resultsfile.delete(); + } + return true; + } + + /** + * Write testargs.txt to the directory where the executable is. + */ + public boolean writeTestargsFile() { + String helper = getMacFileString( ":"+ driver.HELPER_STRING ); + String testfile = getMacFileString( ":"+file.filePath ); + + testargs.writeLine( "-f" ); + testargs.writeLine( helper ); + testargs.writeLine( "-f" ); + testargs.writeLine( testfile ); + testargs.closeLog(); + + return true; + } + + public void close() { + return; + } + /** + * Replace slashes in a string with colons. + * + */ + public String getMacFileString( String path ) { + StringBuffer buffer = new StringBuffer(); + int i; + + for ( i = 0; i < path.length(); i++ ) { + if ( path.charAt(i) == '/' ) { + buffer.append(":"); + } else { + buffer.append( path.charAt(i) ); + } + } + + return buffer.toString(); + } + + + /** + * array of in output file to get attributes of a specific TestCase + */ + public static final String tags[]; + /** + * tag to specify the number of TestCases + */ + public static final String sizeTag = "<#TEST CASES SIZE>"; + /** + * beginning of a tag + */ + public static final String startTag = "<#TEST CASE"; + /** + * end of a tag + */ + public static final String endTag = ">"; + + /** + * creating of String tags[] + */ + static { + String fields[] = { "PASSED", "NAME", "EXPECTED", "ACTUAL", "DESCRIPTION", "REASON", + "BUGNUMBER" }; + + tags = new String[fields.length]; + + for (int i = 0; i < fields.length; ++i) { + tags[i] = startTag + " " + fields[i] + endTag; + } + } +} diff --git a/js/tests/src/com/netscape/javascript/qa/drivers/NavDrv.java b/js/tests/src/com/netscape/javascript/qa/drivers/NavDrv.java new file mode 100644 index 00000000000..8f3a60a8198 --- /dev/null +++ b/js/tests/src/com/netscape/javascript/qa/drivers/NavDrv.java @@ -0,0 +1,243 @@ +package com.netscape.javascript.qa.drivers; + +import netscape.security.PrivilegeManager; +import netscape.javascript.JSObject; + +import java.util.Vector; +import java.util.Date; +import java.io.*; +import java.applet.Applet; + +import com.netscape.javascript.qa.drivers.*; + +/** + * NavDrv is a test driver for running JavaScript tests in Netscape + * Navigator. + * + * NavDrv expects to find test files locally, as well as on an HTTP server, + * since in some tests, JavaScript applications may behave differently with + * local versus cached files. + * + * To run the test without signing the classfiles, add this to the test + * machine's preferences: + *

+ *  user_pref("signed.applets.codebase_principal_support", true);
+ *  
+ * + * The HTML file in which the applet is defined needs to define the following + * parameters: + * + * + * + * + * + * + * + * + * + * + *
Parameter + * Value + *
directory + * full path to the directory in which tests are installed + *
output + * full path to the directory in which log files should be written + *
http_path + * location on an http server in which test files are installed + *
+ * + * @see RhinoDrv + * @author christine@netscape.com + */ +public class NavDrv extends com.netscape.javascript.qa.drivers.TestDriver { + JSObject window; + String SUFFIX = ".html"; + + public NavDrv() { + super(null); + System.out.println( "constructor"); + setSuffix(".html"); + } + + public static void main ( String[] args ) { + PrivilegeManager.enablePrivilege( "UniversalFileAccess" ); + PrivilegeManager.enablePrivilege( "UniversalFileRead" ); + PrivilegeManager.enablePrivilege( "UniversalFileWrite" ); + PrivilegeManager.enablePrivilege( "UniversalPropertyRead" ); + + System.out.println( "main" ); + NavDrv d = new NavDrv(); + d.start(); + } + + public boolean processOptions( ) { + System.out.println( "NavDrv.processOptions()" ); + PrivilegeManager.enablePrivilege( "UniversalFileAccess" ); + PrivilegeManager.enablePrivilege( "UniversalPropertyRead" ); + + window = (JSObject) JSObject.getWindow( this ); + + // Get parameters + + String d = getParameter("directory"); + String o = getParameter("output"); + + HTTP_PATH = getParameter("http_path"); + TEST_DIRECTORY = new File( d ); + OUTPUT_DIRECTORY = new File( o ); + + System.out.println( "http_path: " + HTTP_PATH ); + System.out.println( "directory: " + TEST_DIRECTORY ); + System.out.println( "output: " + OUTPUT_DIRECTORY ); + + if ( ! TEST_DIRECTORY.isDirectory() ) { + System.err.println( "error: " + + TEST_DIRECTORY.getAbsolutePath() +" is not a directory." ); + return false; + } + if ( ! OUTPUT_DIRECTORY.isDirectory() ) { + System.err.println( "error: " + + OUTPUT_DIRECTORY.getAbsolutePath() +" is not a directory." ); + return false; + } + + return true; + } + + public static void openLogFiles( File o ) { + PrivilegeManager.enablePrivilege( "UniversalFileAccess" ); + PrivilegeManager.enablePrivilege( "UniversalFileRead" ); + PrivilegeManager.enablePrivilege( "UniversalFileWrite" ); + PrivilegeManager.enablePrivilege( "UniversalPropertyRead" ); + + TestDriver.openLogFiles( o ); + } + + public Vector getSuites( String[] files ) { + PrivilegeManager.enablePrivilege( "UniversalFileAccess" ); + PrivilegeManager.enablePrivilege( "UniversalPropertyRead" ); + PrivilegeManager.enablePrivilege( "UniversalFileRead" ); + PrivilegeManager.enablePrivilege( "UniversalFileWrite" ); + + return ( super.getSuites( files )); + } + public void getCases( TestSuite suite ) { + PrivilegeManager.enablePrivilege( "UniversalFileAccess" ); + PrivilegeManager.enablePrivilege( "UniversalPropertyRead" ); + PrivilegeManager.enablePrivilege( "UniversalFileRead" ); + PrivilegeManager.enablePrivilege( "UniversalFileWrite" ); + + super.getCases( suite ); + } + + public static TestLog getLog(File output, String filename ) { + PrivilegeManager.enablePrivilege( "UniversalFileAccess" ); + PrivilegeManager.enablePrivilege( "UniversalFileRead" ); + PrivilegeManager.enablePrivilege( "UniversalFileWrite" ); + PrivilegeManager.enablePrivilege( "UniversalPropertyRead" ); + + return TestDriver.getLog( output, filename ); + } + + public void writeLogHeaders( File output ) { + PrivilegeManager.enablePrivilege( "UniversalFileAccess" ); + PrivilegeManager.enablePrivilege( "UniversalFileRead" ); + PrivilegeManager.enablePrivilege( "UniversalFileWrite" ); + PrivilegeManager.enablePrivilege( "UniversalPropertyRead" ); + + super.writeLogHeaders( output ); + } + + public static void writeSuiteResult( TestSuite suite, File output) { + PrivilegeManager.enablePrivilege( "UniversalFileAccess" ); + PrivilegeManager.enablePrivilege( "UniversalFileRead" ); + PrivilegeManager.enablePrivilege( "UniversalFileWrite" ); + PrivilegeManager.enablePrivilege( "UniversalPropertyRead" ); + + TestDriver.writeSuiteResult( suite, output ); + } + + public static void writeSuiteSummary( TestSuite suite, File output) { + PrivilegeManager.enablePrivilege( "UniversalFileAccess" ); + PrivilegeManager.enablePrivilege( "UniversalFileRead" ); + PrivilegeManager.enablePrivilege( "UniversalFileWrite" ); + PrivilegeManager.enablePrivilege( "UniversalPropertyRead" ); + + TestDriver.writeSuiteSummary( suite, output ); + } + + public static void writeFileResult( TestFile file, TestSuite suite, File output) { + PrivilegeManager.enablePrivilege( "UniversalFileAccess" ); + PrivilegeManager.enablePrivilege( "UniversalFileRead" ); + PrivilegeManager.enablePrivilege( "UniversalFileWrite" ); + PrivilegeManager.enablePrivilege( "UniversalPropertyRead" ); + + TestDriver.writeFileResult( file, suite, output ); + } + + public static void writeCaseResults( TestFile file, TestSuite suite, File output) { + PrivilegeManager.enablePrivilege( "UniversalFileAccess" ); + PrivilegeManager.enablePrivilege( "UniversalFileRead" ); + PrivilegeManager.enablePrivilege( "UniversalFileWrite" ); + PrivilegeManager.enablePrivilege( "UniversalPropertyRead" ); + + TestDriver.writeCaseResults( file, suite, output ); + } + + public static void writeDateToLogs( String separator, File output) { + PrivilegeManager.enablePrivilege( "UniversalFileAccess" ); + PrivilegeManager.enablePrivilege( "UniversalFileRead" ); + PrivilegeManager.enablePrivilege( "UniversalFileWrite" ); + PrivilegeManager.enablePrivilege( "UniversalPropertyRead" ); + + TestDriver.writeDateToLogs( separator, output); + } + + + public synchronized void executeSuite( TestSuite suite ) { + PrivilegeManager.enablePrivilege( "UniversalFileAccess" ); + PrivilegeManager.enablePrivilege( "UniversalFileRead" ); + PrivilegeManager.enablePrivilege( "UniversalFileWrite" ); + PrivilegeManager.enablePrivilege( "UniversalPropertyRead" ); + + NavEnv context; + TestFile file; + + for ( int i = 0; i < suite.size(); i++ ) { + synchronized ( suite ) { + file = (TestFile) suite.elementAt( i ); + context = new NavEnv( file, suite, this ); + context.runTest(); + + writeFileResult( file, suite, OUTPUT_DIRECTORY ); + writeCaseResults(file, suite, OUTPUT_DIRECTORY ); + context.close(); + context = null; + + if ( ! file.passed ) { + suite.passed = false; + } + } + } + writeSuiteResult( suite, OUTPUT_DIRECTORY ); + writeSuiteSummary( suite, OUTPUT_DIRECTORY ); + } + + public void stop() { + PrivilegeManager.enablePrivilege( "UniversalFileAccess" ); + PrivilegeManager.enablePrivilege( "UniversalFileRead" ); + PrivilegeManager.enablePrivilege( "UniversalFileWrite" ); + PrivilegeManager.enablePrivilege( "UniversalPropertyRead" ); + + super.stop(); + } + public void start() { + PrivilegeManager.enablePrivilege( "UniversalFileAccess" ); + PrivilegeManager.enablePrivilege( "UniversalFileRead" ); + PrivilegeManager.enablePrivilege( "UniversalFileWrite" ); + PrivilegeManager.enablePrivilege( "UniversalPropertyRead" ); + + super.start(); + } + +} diff --git a/js/tests/src/com/netscape/javascript/qa/drivers/NavEnv.java b/js/tests/src/com/netscape/javascript/qa/drivers/NavEnv.java new file mode 100644 index 00000000000..ed580bb0258 --- /dev/null +++ b/js/tests/src/com/netscape/javascript/qa/drivers/NavEnv.java @@ -0,0 +1,224 @@ +/* -*- Mode: java; tab-width: 8 -*- + * Copyright © 1997, 1998 Netscape Communications Corporation, + * All Rights Reserved. + */ + +package com.netscape.javascript.qa.drivers; + +import java.io.*; + +import netscape.javascript.JSObject; +import com.netscape.javascript.qa.drivers.*; + +/** + * TestEnvironment for running JavaScript tests in Navigator. NavDrv uses + * LiveConnect to create Navigator windows in which JavaScript tests are + * opened and evaluated. + * + * + * @see com.netscape.javascript.qa.drivers.NavDrv + * + * @author christine@netscape.com + * + */ +public class NavEnv implements TestEnvironment { + TestFile file; + TestSuite suite; + NavDrv driver; + private JSObject result; + JSObject opener; + JSObject testcases; + JSObject location; + + boolean evaluatedSuccessfully = false; + JSObject window; + + private String WINDOW_NAME; + + /** + * Constructor a new NavEnv. + */ + public NavEnv( TestFile f, TestSuite s, NavDrv d ) { + this.file = f; + this.suite = s; + this.driver =d; + + this.opener = (JSObject) JSObject.getWindow( d ); + this.window = null; + this.WINDOW_NAME = "js" + getRandomWindowName(); + } + /** + * Called by NavDrv to run the current TestFile. + */ + public synchronized void runTest() { + int i = 0; + System.out.println( file.name ); + try { + createContext(); + file.startTime = driver.getCurrentTime(); + System.out.println( i++ ); + executeTestFile(); + System.out.println( i++ ); + + if ( evaluatedSuccessfully ) { + System.out.println( i++ ); + + parseResult(); + System.out.println( i++ ); + + } + file.endTime = driver.getCurrentTime(); + + } catch ( Exception e ) { + suite.passed = false; + file.passed = false; + file.exception = "file failed with exception: " + e ; + } + } + + /** + * Creates a new JavaScript context, in this case a Navigator window, and + * returns the JSObject associated with that window. + */ + public Object createContext() { + System.out.println( "opening window" ); + opener.eval( WINDOW_NAME +" = window.open( '', '" + WINDOW_NAME + "' )" ); + window = (JSObject) opener.getMember( WINDOW_NAME ); + return window; + } + + /** + * Open the current TestFile in the window by using LiveConnect to set the + * window's location.href property to a URL where the TestFile can be + * found. + */ + public Object executeTestFile() { + System.out.println( "executeTestFile()" ); + try { + location = (JSObject) window.getMember( "location" ); + System.out.println( file.name ); + String s = driver.HTTP_PATH + suite.name +"/" + file.name; + location.setMember( "href", driver.HTTP_PATH + suite.name +"/" + + file.name ); + evaluatedSuccessfully = waitForCompletion(); + + } catch ( Exception e ) { + System.err.println( file.name + " failed with exception: " + e ); + file.exception = e.toString(); + if ( file.name.endsWith( "-n.js" ) ) { + this.file.passed = true; + evaluatedSuccessfully = true; + } else { + this.file.passed = false; + this.suite.passed = false; + evaluatedSuccessfully = false; + } + } + return null; + } + + /** + * Checks the value of the variable "completed", which is set by the + * stopTest() function in each test. + * + * If the stopTest() function is not called in 20 seconds, the test + * fails. + * + * Negative tests will still succeed, since the onerror handler should + * call the stopTest() function. + * + */ + public boolean waitForCompletion() { + int counter = 0; + if ( ! window.getMember( "completed" ).toString().equals("true") ) { + while (!window.getMember("completed").toString().equals("true")) { + try { + if ( counter > 20 ) { + file.passed = false; + file.exception += "test failed to complete"; + System.out.println( "test failed to complete" ); + return false; + } + System.out.println("."); + driver.sleep( 1000 ); + counter++; + } catch ( Exception e ) { + System.out.println( "sleep failed: " + e ); + return false; + } + } + } + return true; + } + + /** + * Use LiveConnect to get the Navigator window's testcases property, which + * is defined in all tests. Parse the testcases array, and create a new + * TestCase object for each TestCase object it finds. + */ + public synchronized boolean parseResult() { + try { + JSObject testcases = (JSObject) window.getMember("testcases"); + file.totalCases = ((Number) ((JSObject) testcases).getMember("length")).intValue(); + System.out.println( "testcases.length is " + file.totalCases ); + for ( int i = 0; i < file.totalCases; i++ ) { + JSObject tc = (JSObject) ((JSObject) testcases).getSlot(i); + + TestCase nc = new TestCase( + tc.getMember("passed") == null ? "null" : tc.getMember("passed").toString(), + tc.getMember("name") == null ? "null " : tc.getMember("name").toString(), + tc.getMember("description") == null ? "null " : tc.getMember("description").toString(), + tc.getMember("expect") == null ? "null " : tc.getMember("expect").toString(), + tc.getMember("actual") == null ? "null " : tc.getMember("actual").toString(), + tc.getMember("reason") == null ? "null " : tc.getMember("reason").toString() + ); + + file.caseVector.addElement( nc ); + + if ( nc.passed.equals("false") ) { + if ( file.name.endsWith( "-n.js" ) ) { + this.file.passed = true; + } else { + this.file.passed = false; + this.suite.passed = false; + } + } + } + } catch ( Exception e ) { + System.out.println( e ); + file.exception = e.toString(); + if ( file.name.endsWith( "-n.html" ) ) { + file.passed = true; + } else { + file.passed = false; + suite.passed = false; + } + } + + // if the file failed, try to get the file's BUGNUMBER. + if ( this.file.passed == false ) { + try { + this.file.bugnumber = window.getMember("BUGNUMBER").toString(); + } catch ( Exception e ) { + // do nothing + } + } + + return true; + } + + /** + * Close Navigator window. + */ + public void close() { + opener.eval( WINDOW_NAME +".close()" ); + opener.eval( "delete " + WINDOW_NAME ); + } + /** + * Generate a random window name, so that each test is associated with a + * unique window. + */ + public String getRandomWindowName() { + return (Integer.toString((new Double(Math.random()*100000)).intValue())); + } +} \ No newline at end of file diff --git a/js/tests/src/com/netscape/javascript/qa/drivers/ObservedTask.java b/js/tests/src/com/netscape/javascript/qa/drivers/ObservedTask.java new file mode 100644 index 00000000000..4ab7af2fb35 --- /dev/null +++ b/js/tests/src/com/netscape/javascript/qa/drivers/ObservedTask.java @@ -0,0 +1,158 @@ +package com.netscape.javascript.qa.drivers; + +import java.io.*; + +/** + * This class is simple utility class that is used to run a process + * which expects no user input. ObserverdTask stores the exit status of + * the process along with standard output and error. + * + * This class is used by the harness only when testing the C version + * of the JavaScript Engine. It is not used by Rhino (JavaScript in + * Java). + * + * @author christine@netscape.com + * @author Nick Lerissa + */ + +public class ObservedTask { + public String commandLine; + + public StringBuffer input = new StringBuffer(); + public StringBuffer error = new StringBuffer(); + int exitValue; + + public Object observer; + + public ObservedTask(String cl, Object observer) { + this.commandLine = cl; + this.observer = observer; + } + + public StringBuffer getInput() { + return input; + } + + public StringBuffer getError() { + return error; + } + + int getExitValue() { + return exitValue; + } + /** + * Execute the process and return when the process is complete. + * + */ + public void exec() throws IOException { + Runtime rt = Runtime.getRuntime(); + + try { + Process proc = rt.exec(commandLine); + OutputStream os = rt.getLocalizedOutputStream(proc.getOutputStream()); + + if ( this.observer instanceof RefEnv ) { + os.write("quit();\n".getBytes()); + } + + os.flush(); + os.close(); + + InputStreamReader is; + + is = new InputStreamReader(proc.getErrorStream()); + (new Thread(new StreamReader(error,is))).start(); + + is = new InputStreamReader(proc.getInputStream()); + (new Thread(new StreamReader(input,is))).start(); + + proc.waitFor(); + exitValue = proc.exitValue(); + + // unfortunately the following pause seems to + // need to be here otherwise we get a crash + + // On AIX, Process.waitFor() doesn't seem to wait for + // the process to complete before continuing. Bad. + // Need to find a workaround. + + if ( System.getProperty("os.name").startsWith("AIX") || + System.getProperty("os.name").startsWith("HP") ) { + pause(20000); + } else { + pause( 10000 ); + } + + } catch ( Exception e ) { + java.lang.System.out.println( e ); + e.printStackTrace(); + } + } + + /** + * Simple print method used for debugging + */ + public void print() { + System.out.println("Input Stream of Process:"); + System.out.println(input); + System.out.println("Error Stream of Process:"); + System.out.println(error); + System.out.println("Exit Value of Process: " + exitValue); + } + + /** + * Simple pause method used for debugging. + */ + static void pause(int length) { + try { + Thread.currentThread().sleep(length); + } catch (InterruptedException ex) { + System.err.println( ex ); + } + } + + /** + * main used for debugging. + */ + static public void main(String args[]) { + if (args.length < 1) { + System.err.println("USAGE: java RunIt "); + System.exit(1); + } + try { + ObservedTask task = new ObservedTask(args[0], null); + task.exec(); + task.print(); + pause(10000); + } catch (Exception e) { + System.err.println("ERROR Exception thrown: " + e); + System.exit(2); + } + } + + /** + * A simple class that reads the contents of and InputStreamReader + * This class is used to read the output and error streams of the process. + */ + class StreamReader implements Runnable { + StringBuffer buffer; + InputStreamReader inputStreamReader; + + StreamReader(StringBuffer b, InputStreamReader i) { + buffer = b; + inputStreamReader = i; + } + + public void run() { + try { + int ch; + while ((ch = inputStreamReader.read()) != -1) { + buffer.append((char) ch); + } + } catch (IOException ex) { + System.err.println("Error IOException thrown " + ex); + ex.printStackTrace(); + } + } + } +} diff --git a/js/tests/src/com/netscape/javascript/qa/drivers/RefDrv.java b/js/tests/src/com/netscape/javascript/qa/drivers/RefDrv.java new file mode 100644 index 00000000000..9e5a1c72f44 --- /dev/null +++ b/js/tests/src/com/netscape/javascript/qa/drivers/RefDrv.java @@ -0,0 +1,256 @@ +/* -*- Mode: java; tab-width: 8 -*- + * Copyright © 1997, 1998 Netscape Communications Corporation, + * All Rights Reserved. + */ + +package com.netscape.javascript.qa.drivers; + +import java.util.Vector; +import java.util.Date; +import java.io.*; +import java.applet.Applet; + +/** + * TestDriver for running the JavaScript conformance tests against the + * JavaScript engine implemenation in C, A.K.A. js/ref, Monkey. + * + *

+ * + * For each test program, RefDrv creates a RefEnv. RefEnv in turn calls the + * JavaScript shell executable (jsshell.exe), passing the helper file and the + * test file as arguments. + * + *

+ * + * RefEnv reads the output of the jsshell process. You must use the + * jsref.js helper file, which formats the printed output of each + * test in a way that RefEnv can parse. + * + *

RefEnv expects the following command line options: +

+    -c  1 or 0; whether or not to use code coverage
+    -e  Full path to jsshell.exe
+    -d  Path to the directory where the tests are installed
+    -h  Path to the helper file (jsref.js)
+    -s  List of suites to execute (optional)
+    -o  Directory in which log files should be written (optional)
+    -t  
+    
+ + * For example, the following command line will run the tests in + * c:\src\ns\js\tests\ecma\Math and c:\src\ns\js\tests\ecma\Number against + * the jsshell executable found in c:\src\js\ref + * +
+    java -classpath %CLASSPATH% com.netscape.javascript.qa.drivers.RefDrv 
+    -d c:\src\ns\js\tests\ecma\ -h c:\src\ns\js\tests\ecma\jsref.js 
+    -e c:\src\js\ref\jsshell.exe  -s Math Number
+    
+ * @see com.netscape.javascript.qa.drivers.TestDriver + * @see com.netscape.javascript.qa.drivers.RhinoDrv + * + * @author christine@netscape.com + * @author Nick Lerissa + * + */ + +public class RefDrv extends TestDriver { + String SUFFIX = ".js"; + boolean CODE_COVERAGE = false; + String HELPER_STRING; + + /** + * Create a new RefDrv. + * + * @param args the arguments passed to the main method. + */ + + public RefDrv( String[] args) { + super( args ); + setSuffix( ".js"); + } + + /** + * RefDrv expects the following options: +
+        -e full path to the JavaScript executable
+        -d directory in which tests are installed
+        -h path to helper functions file (jsref.js)
+        -o directory in which log files will be written
+        -s list of Suites that should be executed
+        
+ */ + + public static void main ( String[] args ) { + RefDrv d = new RefDrv( args ); + d.start(); + } + /** + * Process command line options. + * + * @see com.netscape.javascript.qa.drivers.RhinoDrv#processOptions + */ + + public boolean processOptions() { + int length = ARGS.length; + + if (ARGS[0].startsWith("-")) { + //XXX need to verify that we at least get valid d and -h options + + for (int i=0; i < ARGS.length; i++ ) { + if ( ARGS[i].equals("-d") ) { + p( "-d " ); + + this.TEST_DIRECTORY = ARGS[i].endsWith(File.separator) + ? new File( ARGS[++i] ) + : new File( ARGS[++i] + File.separator ); + p( "-d " +this.TEST_DIRECTORY ); + + if ( ! ( this.TEST_DIRECTORY ).isDirectory() ) { + p( "error: " + + this.TEST_DIRECTORY.getAbsolutePath() + + " is not a TEST_DIRECTORY." ); + return false; + } else { + continue; + } + } + if ( ARGS[i].equals("-s") ) { + p( "-s "); + FILES = new String[20] ; + for ( int j = ++i, k=0; j < ARGS.length; j++ ) { + if ( ARGS[j].startsWith("-") ){ + break; + } + FILES[k++] = ARGS[j]; + } + } + if ( ARGS[i].equals("-h") ) { + p( "-h" ); + this.HELPER_STRING = new String( ARGS[++i] ); + this.HELPER_FUNCTIONS = new File( HELPER_STRING ); + if ( ! (this.HELPER_FUNCTIONS ).isFile() ) { + p( "error: "+ + this.HELPER_FUNCTIONS.getAbsolutePath()+ + " file not found." ); + return false; + } + p( "-h " +this.HELPER_FUNCTIONS ); + } + if ( ARGS[i].equals("-c")) { + p("-c"); + this.CODE_COVERAGE = new Boolean( ARGS[++i] ).booleanValue(); + } + if ( ARGS[i].equals("-o") ) { + p( "-o" ); + OUTPUT_DIRECTORY = new File(ARGS[++i]+File.separator); + if ( !OUTPUT_DIRECTORY.exists() || + !OUTPUT_DIRECTORY.isDirectory() ) + { + p( "error: "+ + OUTPUT_DIRECTORY.getAbsolutePath()+ + " is not a directory."); + return false; + } + } + + if ( ARGS[i].equals("-p") ) { + this.OPT_LEVEL = Integer.parseInt( ARGS[++i] ); + } + + if ( ARGS[i].equals("-db" )) { + this.DEBUG_LEVEL = Integer.parseInt( ARGS[++i] ); + this.OPT_LEVEL = 0; + } + + if ( ARGS[i].equals("-e")) { + this.EXECUTABLE = ARGS[++i]; + } + if ( ARGS[i].equals("-t")) { + String __tinderbox = ARGS[++i]; + + if ( __tinderbox.equals("true") || __tinderbox.equals("1")){ + this.TINDERBOX = true; + } else { + this.TINDERBOX = false; + } + } + } + + return true; + + } else { + + switch ( ARGS.length ) { + case 0: + p( "error: specify location of JavaScript "+ + "tests" ); + return false; + case 1: + p( "error: specify location of JavaScript "+ + "HELPER_FUNCTIONS file" ); + return false; + case 2: + this.TEST_DIRECTORY = ARGS[0].endsWith(File.separator) + ? new File( ARGS[0] ) + : new File( ARGS[0] + File.separator ); + this.HELPER_FUNCTIONS = new File( ARGS[1] ); + if ( ! ( this.TEST_DIRECTORY ).isDirectory() ) { + p( "error: " + + this.TEST_DIRECTORY.getAbsolutePath() +" is not a directory." ); + return false; + } + if ( ! (this.HELPER_FUNCTIONS ).isFile() ) { + p( "error: "+ + this.HELPER_FUNCTIONS.getAbsolutePath()+ + " file not found." ); + return false; + } + return true; + default: + p( "could not understand arguments." ); + return false; + } + } + } + /** + * For each TestFile in each TestSuite, create a new RefEnv, run the + * test, parse its results, and close the RefEnv. + */ + + public synchronized void executeSuite( TestSuite suite ) { + TestEnvironment context; + TestFile file; + + p("executing suite" ); + try { + for ( int i = 0; i < suite.size(); i++ ) { + synchronized ( suite ) { + file = (TestFile) suite.elementAt( i ); + + if ( getSystemInformation()[0].startsWith( "Mac" )) { + context = new MacRefEnv( file, suite, this ); + ((MacRefEnv) context).runTest(); + } else { + context = new RefEnv( file, suite, this ); + ((RefEnv) context).runTest(); + } + } + + writeFileResult( file, suite, OUTPUT_DIRECTORY ); + writeCaseResults(file, suite, OUTPUT_DIRECTORY ); + context.close(); + context = null; + + if ( ! file.passed ) { + suite.passed = false; + } + } + } catch ( Exception e ) { + e.printStackTrace() ; + } + writeSuiteResult( suite, OUTPUT_DIRECTORY ); + writeSuiteSummary( suite, OUTPUT_DIRECTORY ); + } +} + diff --git a/js/tests/src/com/netscape/javascript/qa/drivers/RefEnv.java b/js/tests/src/com/netscape/javascript/qa/drivers/RefEnv.java new file mode 100644 index 00000000000..945fb9ce6c1 --- /dev/null +++ b/js/tests/src/com/netscape/javascript/qa/drivers/RefEnv.java @@ -0,0 +1,295 @@ +/* -*- Mode: java; tab-width: 8 -*- + * Copyright © 1997, 1998 Netscape Communications Corporation, + * All Rights Reserved. + */ + +package com.netscape.javascript.qa.drivers; + +import java.io.*; +import java.util.StringTokenizer; + +/** + * RefEnv is used to run a JavaScript test in the JavaScript engine + * implemented in C. RefEnv creates a new ObservedTask and processes + * the standard output and standard error of the tests to determine the + * test result. The RefDrv expects the process output to contain the + * following content: + * + *

+ * 1 - anything (before the formatted output can be unstructured. + * + *

+ * + * 2 - the number of test cases output in the following way. + *

+ *    <#TEST CASES SIZE>
+ *    int
+ *  
+ * + * 3 - the results of each test formatted in the following way + * (name, expected, actual, description, and reason can all be multilines) + *
+ *    <#TEST CASE PASSED>
+ *    true|false
+ *    <#TEST CASE NAME>
+ *    text
+ *    <#TEST CASE EXPECTED>
+ *    text
+ *    <#TEST CASE ACTUAL>
+ *    text
+ *    <#TEST CASE DESCRIPTION>
+ *    text
+ *    <#TEST CASE REASON>
+ *    text
+ *    <#TEST CASE BUGNUMBER>
+ *    text
+ *  
+ * + * 4 - a marker that signifies the end of the tests + * + *
+ *    <#TEST CASES DONE>
+ *  
+ + * 5 - after the end of the tests you can have more unstructed text. + *

+ * The test case output is generated by the stopTest function, which is in + * the shared functions file, jsref.js. + * + * @see com.netscape.javascript.qa.drivers.TestEnvironment + * @see ObservedTask + * + * @author christine@netscape.com + * @author Nick Lerissa + */ +public class RefEnv implements TestEnvironment { + TestFile file; + TestSuite suite; + RefDrv driver; + ObservedTask task; + + /** + * Create a new RefEnv. + */ + public RefEnv( TestFile f, TestSuite s, RefDrv d) { + this.file = f; + this.suite = s; + this.driver = d; + } + + /** + * Called by the driver to execute the test program. + */ + public void runTest() { + driver.p( file.name ); + try { + file.startTime = driver.getCurrentTime(); + createContext(); + executeTestFile(); + file.endTime = driver.getCurrentTime(); + + if (task.getExitValue() != 0) { + if ( file.name.endsWith( "-n.js" )) { + file.passed = true; + } else { + suite.passed = false; + file.passed = false; + } + } + if ( ! parseResult() ) { + if ( file.name.endsWith( "-n.js" ) ) { + file.passed = true; + } else { + suite.passed = false; + file.passed = false; + } + file.exception = new String(task.getError()); + } + + } catch ( Exception e ) { + suite.passed = false; + file.passed = false; + file.exception = "Unknown process exception."; +/* + file.exception = new String(task.getError()) + + " exit value: " + task.getExitValue() + + "\nThrew Exception:" + e; +*/ + } + } + + /** + * Instantiate a new JavaScript shell, passing the TestFile as an + * argument. + * + */ + public Object createContext() { + if ( driver.CODE_COVERAGE ) { + String command = "coverage " + + "/SaveMergeData /SaveMergeTextData "+ + driver.EXECUTABLE + " -f " + + driver.HELPER_FUNCTIONS.getAbsolutePath() + " -f " + + file.filePath; + + System.out.println( "command is " + command ); + + task = new ObservedTask( command, this ); + } else { + task = new ObservedTask( driver.EXECUTABLE + " -f " + + driver.HELPER_FUNCTIONS.getAbsolutePath() + " -f " + + file.filePath, this); + } + return (Object) task; + } + /** + * Start the shell process. + * + */ + public Object executeTestFile() { + try { + task.exec(); + } catch ( IOException e ) { + driver.p( e.toString() ); + file.exception = e.toString(); + e.printStackTrace(); + } + return null; + } + + /** + * Parse the standard output of the process, and try to create new + * TestCase objects. + */ + public boolean parseResult() { + String line; + int i,j; + + BufferedReader br = new BufferedReader(new StringReader( + new String(task.getInput()))); + try { + do { + line = br.readLine(); + driver.p( line ); + + if (line == null) { + driver.p("\tERROR: No lines to read"); + return false; + } + } while (!line.equals(sizeTag)); + + if ((line = br.readLine()) == null) + return false; + + file.totalCases = Integer.valueOf(line).intValue(); + + if ((line = br.readLine()) == null) { + driver.p("\tERROR: No lines after " + sizeTag); + return false; + } + + } catch (NumberFormatException nfe) { + driver.p("\tERROR: No integer after " + sizeTag); + return false; + } catch ( IOException e ) { + driver.p( "Exception reading process output:" + e.toString() ); + file.exception = e.toString(); + return false; + } + + for ( i = 0; i < file.totalCases; i++) { + String values[] = new String[tags.length]; + try { + for ( j = 0; j < tags.length; j++) { + values[j] = null; + + if (!line.startsWith(tags[j])) { + driver.p("line didn't start with " + tags[j] +":"+line); + return false; + } + while (((line = br.readLine()) != null) && + (!(line.startsWith(startTag)))) + { + values[j] = (values[j] == null) ? line : (values[j] + + "\n" + line); + } + if (values[j] == null) values[j] = ""; + } + if ((line == null) && (i < file.totalCases - 1)) { + driver.p("line == null and " + i + "<" + + (file.totalCases - 1)); + return false; + } + } catch ( IOException e ) { + driver.p( "Exception reading process output: " + e ); + file.exception = e.toString(); + return false; + } + + TestCase rt = new TestCase(values[0],values[1],values[4],values[2], + values[3],values[5]); + + file.bugnumber = values[6]; + file.caseVector.addElement( rt ); + + if ( rt.passed.equals("false") ) { + if ( file.name.endsWith( "-n.js" ) ) { + this.file.passed = true; + } else { + this.file.passed = false; + this.suite.passed = false; + } + } + + } + + if ( file.totalCases == 0 ) { + if ( file.name.endsWith( "-n.js" ) ) { + this.file.passed = true; + } else { + this.file.reason = "File contains no testcases. " + this.file.reason; + this.file.passed = false; + this.suite.passed = false; + } + } + + return true; + } + /** + * Method required by TestEnvironment; this implemenation does nothing. + * + */ + public void close(){ + return; + } + + /** + * array of in output file to get attributes of a specific TestCase + */ + public static final String tags[]; + /** + * tag to specify the number of TestCases + */ + public static final String sizeTag = "<#TEST CASES SIZE>"; + /** + * beginning of a tag + */ + public static final String startTag = "<#TEST CASE"; + /** + * end of a tag + */ + public static final String endTag = ">"; + + /** + * creating of String tags[] + */ + static { + String fields[] = { "PASSED", "NAME", "EXPECTED", "ACTUAL", "DESCRIPTION", "REASON", + "BUGNUMBER" }; + + tags = new String[fields.length]; + + for (int i = 0; i < fields.length; ++i) { + tags[i] = startTag + " " + fields[i] + endTag; + } + } +} \ No newline at end of file diff --git a/js/tests/src/com/netscape/javascript/qa/drivers/RhinoDrv.java b/js/tests/src/com/netscape/javascript/qa/drivers/RhinoDrv.java new file mode 100644 index 00000000000..6f68b6a4d20 --- /dev/null +++ b/js/tests/src/com/netscape/javascript/qa/drivers/RhinoDrv.java @@ -0,0 +1,219 @@ +/* Copyright © 1997, 1998 Netscape Communications Corporation, + * All Rights Reserved. + */ + +package com.netscape.javascript.qa.drivers; + +import java.io.File; + +import org.mozilla.javascript.*; + +/** + RhinoDrv is an application for executing JavaScript tests against the + JavaScript engine implemented in Java. + +

+ + The application requires two arguments: +

+ + For example: +
+
+    java -classpath /tmp/Rhino/:/tmp/tests COM.netscape.javascript.qa.RhinoDrv 
+    /tmp/tests/ecma/ /tmp/tests/ecma/shell.js
+
+    
+ +

+ + Alternatively, you can specify one or many of the suites by using the + following command-line options: + +

+    -d        Directory in which suites are located
+    -s        Names of suites to execute
+    -h        Name of helper file
+    -p        Optimization level
+    -o        Output directory
+    -db       Debug level
+    -t        Whether or not we're using tinderbox
+
+    
+ + For example: +
+
+    java -classpath $CLASSPATH com.netscape.javascript.qa.drivers.RhinoDrv -d c:\src\ns\js\tests\ecma\ -s Math Number Function -h shell.js -p 2 -db 0
+
+    
+ + @see TestDriver + @author christine@netscape.com + + */ + +public class RhinoDrv extends TestDriver { + public final String SUFFIX = ".js"; + + /** + * + * + */ + + public RhinoDrv( String[] args) { + super( args ); + setSuffix(".js"); + + } + public static void main ( String[] args ) { + RhinoDrv d = new RhinoDrv( args ); + d.start(); + } + public boolean processOptions() { + int length = ARGS.length; + if (ARGS[0].startsWith("-")) { + //XXX need to verify that we at least get valid d and -h options + + for (int i=0; i < ARGS.length; i++ ) { + if ( ARGS[i].equals("-t")) { + String __tinderbox = ARGS[++i]; + + if ( __tinderbox.equals("true") || __tinderbox.equals("1")){ + TestDriver.TINDERBOX = true; + } else { + TestDriver.TINDERBOX = false; + } + } + + if ( ARGS[i].equals("-d") ) { + p( "-d " ); + + this.TEST_DIRECTORY = ARGS[i].endsWith(File.separator) + ? new File( ARGS[++i] ) + : new File( ARGS[++i] + File.separator ); + p( "-d " +this.TEST_DIRECTORY ); + + if ( ! ( this.TEST_DIRECTORY ).isDirectory() ) { + System.err.println( "error: " + + this.TEST_DIRECTORY.getAbsolutePath() +" is not a TEST_DIRECTORY." ); + return false; + } else { + continue; + } + } + if ( ARGS[i].equals("-s") ) { + p( "-s "); + FILES = new String[20] ; + for ( int j = ++i, k=0; j < ARGS.length; j++ ) { + if ( ARGS[j].startsWith("-") ){ + break; + } + FILES[k++] = ARGS[j]; + } + } + if ( ARGS[i].equals("-h") ) { + p( "-h" ); + this.HELPER_FUNCTIONS = new File( ARGS[++i] ); + if ( ! (this.HELPER_FUNCTIONS ).isFile() ) { + System.err.println( "error: "+ this.HELPER_FUNCTIONS.getAbsolutePath()+ + " file not found." ); + return false; + } + } + if ( ARGS[i].equals("-o") ) { + p( "-o" ); + OUTPUT_DIRECTORY = new File(ARGS[++i]+File.separator); + if ( !OUTPUT_DIRECTORY.exists() || !OUTPUT_DIRECTORY.isDirectory() ) { + System.err.println( "error: "+OUTPUT_DIRECTORY.getAbsolutePath()+ + " is not a directory."); + return false; + } + } + + if ( ARGS[i].equals("-p") ) { + OPT_LEVEL = Integer.parseInt( ARGS[++i] ); + } + + if ( ARGS[i].equals("-db" )) { + DEBUG_LEVEL = Integer.parseInt( ARGS[++i] ); + OPT_LEVEL = 0; + } + + if ( ARGS[i].equals("-e")) { + EXECUTABLE = ARGS[++i]; + } + } + + return true; + + } else { + + switch ( ARGS.length ) { + case 0: + System.err.println( "error: specify location of JavaScript "+ + "tests" ); + return false; + case 1: + System.err.println( "error: specify location of JavaScript "+ + "HELPER_FUNCTIONS file" ); + return false; + case 2: + this.TEST_DIRECTORY = ARGS[0].endsWith(File.separator) + ? new File( ARGS[0] ) + : new File( ARGS[0] + File.separator ); + this.HELPER_FUNCTIONS = new File( ARGS[1] ); + if ( ! ( this.TEST_DIRECTORY ).isDirectory() ) { + System.err.println( "error: " + + this.TEST_DIRECTORY.getAbsolutePath() +" is not a directory." ); + return false; + } + if ( ! (this.HELPER_FUNCTIONS ).isFile() ) { + System.err.println( "error: "+ this.HELPER_FUNCTIONS.getAbsolutePath()+ + " file not found." ); + return false; + } + return true; + default: + System.err.println( "could not understand arguments." ); + return false; + } + } + } + + /** + * For each file in each suite, create a new RhinoEnv. + */ + + public synchronized void executeSuite( TestSuite suite ) { + RhinoEnv context; + TestFile file; + + for ( int i = 0; i < suite.size(); i++ ) { + synchronized ( suite ) { + file = (TestFile) suite.elementAt( i ); + + context = new RhinoEnv( file, suite, this ); + + context.runTest(); + + writeFileResult( file, suite, OUTPUT_DIRECTORY ); + writeCaseResults(file, suite, OUTPUT_DIRECTORY ); + context.close(); + context = null; + + if ( ! file.passed ) { + suite.passed = false; + } + } + } + writeSuiteResult( suite, OUTPUT_DIRECTORY ); + writeSuiteSummary( suite, OUTPUT_DIRECTORY ); + } +} \ No newline at end of file diff --git a/js/tests/src/com/netscape/javascript/qa/drivers/RhinoEnv.java b/js/tests/src/com/netscape/javascript/qa/drivers/RhinoEnv.java new file mode 100644 index 00000000000..580dd959a3f --- /dev/null +++ b/js/tests/src/com/netscape/javascript/qa/drivers/RhinoEnv.java @@ -0,0 +1,257 @@ +package com.netscape.javascript.qa.drivers; + +import java.io.*; +import com.netscape.javascript.*; +import org.mozilla.javascript.*; +import org.mozilla.javascript.tools.shell.Main; + +/** + This class creates a javax.javascript.Context, which evaluates + the helper and RhinoFile and returns a result. + +

+ + If the test throws a Java exception or JavaScript runtime or + compilation error, the RhinoFile fails, and the exception is stored + in that RhinoFile's exception variable. + +

+ + If the test succeeds, the result is parsed and the RhinoFile's test + result variables are populated. + + @author christine@netscape.com + +*/ +public class RhinoEnv implements TestEnvironment { + public Main global; + Object cx; + Object result; + TestDriver driver; + TestSuite suite; + TestFile file; + + /** + + @param f RhinoFile that will be executed in this RhinoEnv + @param s the RhinoFile's test suite + @param d the RhinoDrv applet that created this RhinoEnv + + */ + public RhinoEnv( TestFile f, TestSuite s, TestDriver d) { + this.file = f; + this.suite = s; + this.driver = d; + } + /** + Creates the JavaScript Context, which evaluates the contents of a + RhinoFile and returns a result. The RhinoEnv parses the test + result, and sets values of the RhinoFile test result properties. + + @see com.netscape.javascript.Context#setOptimizationLevel + @see com.netscape.javascript.Context#setDebugLevel + + */ + public synchronized void runTest() { + this.driver.p( file.name ); + try { + cx = createContext(); + ((Context) cx).setOptimizationLevel( driver.OPT_LEVEL ); + ((Context) cx).setDebugLevel( driver.DEBUG_LEVEL ); + Object loadFn = executeTestFile(driver.HELPER_FUNCTIONS.getAbsolutePath()); + + file.startTime = driver.getCurrentTime(); + result = executeTestFile( file.filePath ); + file.endTime = driver.getCurrentTime(); + parseResult(); + + } catch ( Exception e ) { + suite.passed = false; + file.passed = false; + file.exception += "file failed with exception: " + e ; + } + } + /** + * Create a new com.netscape.javascript.Context. + * + * @return the newly instantiated Context + * + */ + public Object createContext() { + // this is stolen from Main.java + cx = new Context(); + ((Context) cx).enter(); + + global = new Main(); + ((Context) cx).initStandardObjects(global); + + String[] names = { "print", "quit", "version", "load", "help", + "loadClass" }; + try { + global.defineFunctionProperties(names, Main.class, + ScriptableObject.DONTENUM); + } catch (PropertyException e) { + + throw new Error(e.getMessage()); + } + + return cx; + } + public Object executeTestFile() { + return null; + } + + /** + Given a filename, evaluate the file's contents as a JavaScript + program. Return the value of the program. If the test throws + a Java exception or JavaScript runtime or compilation error, + return the string value of the error message. + + @param s full path to the file that will be exectued. + @return test result object. If the test is positive, result + should be an instance of Scriptable. if the test is negative, + the result should be a String, whose value is the message in the + JavaScript error or Java exception. + */ + public Object executeTestFile( String s ) { + // this bit is stolen from Main.java + FileReader in = null; + try { + in = new FileReader( s ); + } catch (FileNotFoundException ex) { + driver.p("couldn't open file " + s); + } + + Object result = null; + + try { + // Here we evalute the entire contents of the file as + // as script. Text is printed only if the print() function + // is called. + // cx.evaluateReader((Scriptable) global, in, args[i], 1, null); + + result = ((Scriptable) (((Context) cx).evaluateReader( + (Scriptable) global, (Reader) in, s, 1, null))); + + } catch (WrappedException we) { + driver.p("Wrapped Exception: "+ + we.getWrappedException().toString()); + result = we.getWrappedException().toString(); + } catch (Exception jse) { + driver.p("JavaScriptException: " + jse.getMessage()); + result = jse.getMessage(); + } + + return ( result ); + } + /** + Evaluates the RhinoFile result. If the result is an instance of + javax.javascript.Scriptable, assume it is a JavaScript Array of + TestCase objects, as described in RhinoDrv.java. For each test case in + the array, add an element to the RhinoFile's test case vector. If all + test cases passed, set the RhinoFile's passed value to true; else set + its passed value to false. + +

+ + If the result is not a Scriptable object, the test failed. Set the the + RhinoFile's exception property to the string value of the result. + However, negative tests, which should have a "-n.js" extension, are + expected to fail. + + */ + public boolean parseResult() { + FlattenedObject fo = null; + + if ( result instanceof Scriptable ) { + fo = new FlattenedObject( (Scriptable) result ); + + try { + file.totalCases = ((Number) fo.getProperty("length")).intValue(); + for ( int i = 0; i < file.totalCases; i++ ) { + Scriptable tc = (Scriptable) ((Scriptable) result).get( i, + (Scriptable) result); + + TestCase rt = new TestCase( + getString(tc.get( "passed", tc )), + getString(tc.get( "name", tc )), + getString(tc.get( "description", tc )), + getString(tc.get( "expect", tc )), + getString(tc.get( "actual", tc )), + getString(tc.get( "reason", tc )) + ); + + file.bugnumber= + (getString(tc.get("bugnumber", tc))).startsWith + ("com.netscape.javascript") + ? file.bugnumber + : getString(tc.get("bugnumber", tc)); + + file.caseVector.addElement( rt ); + if ( rt.passed.equals("false") ) { + this.file.passed = false; + this.suite.passed = false; + } + } + + if ( file.totalCases == 0 ) { + if ( file.name.endsWith( "-n.js" ) ) { + this.file.passed = true; + } else { + this.file.reason = "File contains no testcases. " + this.file.reason; + this.file.passed = false; + this.suite.passed = false; + } + } + + } catch ( Exception e ) { + this.file.exception = "Got a Scriptable result, but failed "+ + "parsing its arguments. Exception: " + e.toString() + + " Flattened Object is: " + fo.toString(); + + this.file.passed = false; + this.suite.passed = false; + + return false; + } + } else { + // if it's not a scriptable object, test failed. set the file's + // exception to the string value of whatever result we did get. + this.file.exception = result.toString(); + + // if the file's name ends in "-n", the test expected an error. + + if ( file.name.endsWith( "-n.js" ) ) { + this.file.passed = true; + } else { + this.file.passed = false; + this.suite.passed = false; + return false; + } + } + + return true; + } + /** + Close the context. + */ + public void close() { + try { + ((Context) cx).exit(); + } catch ( Exception e ) { + suite.passed = false; + file.passed = false; + file.exception = "file failed with exception: " + e ; + } + + } + /** + * Get the JavaScript string associated with a JavaScript object. + * + * @param object a Java identifier for a JavaScript object + * @return the JavaScript string representation of the object + */ + public String getString( Object object ) { + return (((Context) cx).toString( object )); + } +} diff --git a/js/tests/src/com/netscape/javascript/qa/drivers/TestCase.java b/js/tests/src/com/netscape/javascript/qa/drivers/TestCase.java new file mode 100644 index 00000000000..263f989a209 --- /dev/null +++ b/js/tests/src/com/netscape/javascript/qa/drivers/TestCase.java @@ -0,0 +1,52 @@ +/* -*- Mode: java; tab-width: 8 -*- + * Copyright © 1997, 1998 Netscape Communications Corporation, + * All Rights Reserved. + */ + +package com.netscape.javascript.qa.drivers; + +/** + * Equivalent to the JavaScript TestCase object as described in + * TestDriver.java. For each test case in a TestFile, a TestCase object is + * created and added to the TestFile's caseVector. + * + * @see com.netscape.javascript.qa.drivers.TestDriver + * @see com.netscape.javascript.qa.drivers.TestEnvironment + * + * @author christine@netscape.com + */ + +public class TestCase { + public String passed; + public String name; + public String description; + public String expect; + public String actual; + public String reason; + + /** + * Create a new TestCase object. + * + * @param passed "true" if the test case passed, otherwise "false" + * @param name label associated with the test case + * @param description string showing what got tested, usually JavaScript + * code + * @param expect string representation of the expected result + * @param actual string representation of the actual result + * @param reason reason for test failure + * + * @see com.netscape.javascript.qa.drivers.TestDriver + * @see com.netscape.javascript.qa.drivers.TestEnvironment + * + */ + public TestCase( String passed, String name, String description, + String expect, String actual, String reason ) { + + this.passed = passed; + this.name = name; + this.description = description; + this.expect = expect; + this.actual = actual; + this.reason = reason; + } +} diff --git a/js/tests/src/com/netscape/javascript/qa/drivers/TestDriver.java b/js/tests/src/com/netscape/javascript/qa/drivers/TestDriver.java new file mode 100644 index 00000000000..e6c87d82469 --- /dev/null +++ b/js/tests/src/com/netscape/javascript/qa/drivers/TestDriver.java @@ -0,0 +1,907 @@ +/* -*- Mode: java; tab-width: 8 -*- + * Copyright © 1997, 1998 Netscape Communications Corporation, + * All Rights Reserved. + */ + +package com.netscape.javascript.qa.drivers; + +import java.util.Vector; +import java.util.Date; +import java.io.*; +import java.applet.Applet; + +/** + * Parent class for JavaScript test drivers. Subclasses run tests against + * the JavaScript engine in C, Java, and its embedding in Navigator. + * + *

+ * + * The default implementation does nothing, but contains methods that are + * used by all subclasses. + +

+ + The JavaScript test suite is extendable. To write a new JavaScript test, + your test program must call a function that returns array of TestCase objects. + The TestCase object is defined in shell.js: +

+    function TestCase( n, d, e, a ) {
+        this.name        = n;
+        this.description = d;
+        this.expect      = e;
+        this.actual      = a;
+        this.passed      = true;
+        this.reason      = "";
+        this.passed = getTestCaseResult( this.expect, this.actual );
+    }
+    
+ + In your test program you should: + + + + To add new test to the suite: + + + */ + +public class TestDriver extends Applet implements Runnable { + Thread THREAD = null; + + String[] SYSTEM; + + File TEST_DIRECTORY; + File HELPER_FUNCTIONS; + File OUTPUT_DIRECTORY; + + String HTTP_PATH; + String SUFFIX; + + int OPT_LEVEL; + int DEBUG_LEVEL; + + String[] ARGS; + + String EXECUTABLE = null; + + Vector SUITES; + String[] FILES; + + public static boolean TINDERBOX = false; + + public static final boolean DEBUG = true; + public static final boolean TCMS = false; + + Runtime RUNTIME; + + long FREE_MEMORY; + long TOTAL_MEMORY; + + public TestDriver( String[] args ) { + this.ARGS = args; + if ( THREAD == null ) { + THREAD = new Thread(this); + THREAD.start(); + } + } + public void run() { + } + + public void start() { + this.FILES = null; + this.OUTPUT_DIRECTORY = null; + this.OPT_LEVEL = 0; + this.DEBUG_LEVEL=0; + this.RUNTIME = Runtime.getRuntime(); + this.FREE_MEMORY = RUNTIME.freeMemory(); + this.TOTAL_MEMORY = RUNTIME.totalMemory(); + + if ( processOptions() ) { + + openLogFiles( OUTPUT_DIRECTORY == null ? TEST_DIRECTORY : + OUTPUT_DIRECTORY); + + writeDateToLogs("
", OUTPUT_DIRECTORY ); + writeLogHeaders( OUTPUT_DIRECTORY ); + + if (FILES == null) { + FILES = TEST_DIRECTORY.list(); + } + + if ( TestDriver.TINDERBOX ) { + writeTinderboxHeader(EXECUTABLE); + } + + SUITES = getSuites( FILES ); + + for ( int i = 0; i < SUITES.size(); i++ ) { + getCases((TestSuite) SUITES.elementAt(i)); + } + for ( int i = 0; i < SUITES.size(); i++ ) { + if (TestDriver.TINDERBOX) { + writeTinderboxSuiteName((TestSuite) SUITES.elementAt(i)); + } + executeSuite((TestSuite) SUITES.elementAt(i)); + if (TestDriver.TINDERBOX) { + writeTinderboxSuiteResult((TestSuite) SUITES.elementAt(i)); + } + RUNTIME.gc(); + } + } + stop(); + } + /** + * Close all logs. + */ + + public void stop() { + closeLogs(); + RUNTIME.gc(); + long NEW_FREE_MEMORY = RUNTIME.freeMemory(); + long NEW_TOTAL_MEMORY = RUNTIME.totalMemory(); + + String string = ""+ + "Free Memory " + NEW_FREE_MEMORY + "\n
"+ + "Total Memory " + NEW_TOTAL_MEMORY +"\n
"+ + "Free Leaked " + (FREE_MEMORY - NEW_FREE_MEMORY) +"\n
"+ + "Total Leaked " + (TOTAL_MEMORY- NEW_TOTAL_MEMORY) +"\n
"+ + "
"; + + p( string ); + p("done!"); + + if ( THREAD != null ) { + THREAD.stop(); + THREAD = null; + } + } + + public void closeLogs() { + writeDateToLogs( "", OUTPUT_DIRECTORY ); + getLog( OUTPUT_DIRECTORY, SUMMARY_LOG_NAME ).closeLog(); + getLog( OUTPUT_DIRECTORY, SUITE_LOG_NAME ).closeLog(); + getLog( OUTPUT_DIRECTORY, FILE_LOG_NAME).closeLog(); + getLog( OUTPUT_DIRECTORY, CASE_LOG_NAME).closeLog(); + + if ( DEBUG ) { + getLog( OUTPUT_DIRECTORY, DEBUG_LOG_NAME ).closeLog(); + } + } + + /** + * Get information about the operating system. + */ + public static String[] getSystemInformation() { + String [] SYSTEM = { System.getProperty( "os.name" ), + System.getProperty( "os.arch" ), + System.getProperty( "os.version" ) }; + return SYSTEM; + } + + /** + * + * + * @return a file object with the specified in the output directory. + */ + + public static TestLog getLog(File output, String filename ) { + enablePrivileges(); + TestLog log = null; + String[] SYSTEM = getSystemInformation(); + +// String platform = ( SYSTEM[0].length() < 4 ) ? SYSTEM[0] : SYSTEM[0].substring(0,4); + + String platform = SYSTEM[0]; + + try { + File logdir = new File( + output.getAbsolutePath() + + (output.getAbsolutePath().endsWith(File.separator) ? "" : File.separator) + + platform + + SYSTEM[1] +"-"+ SYSTEM[2], + getCurrentDate("_") ); + logdir.mkdirs(); + log = new TestLog( logdir.getAbsolutePath() + File.separator + + filename, TERMINATOR ); + } catch ( Exception e ) { + p( "TestDriver.getLog threw " + e.toString() ); + p( "platform " + platform ); + p( "output" + output.toString() ); + p( "filename " + filename.toString() ); + p( "File.separator " + File.separator.toString() ); + p( "SYSTEM[0] " + SYSTEM[0] ); + p( "SYSTEM[1] " + SYSTEM[1] ); + p( "SYSTEM[2] " + SYSTEM[2] ); + p( "date " +getCurrentDate("_") ); + + e.printStackTrace(); + } + + return log; + + } + + /** + * Create and write headers to log files. + * + * @param output directory in which output files are written. + */ + + public static void openLogFiles( File output ) { + enablePrivileges(); + + TestLog SUMMARY_LOG = getLog( output, SUMMARY_LOG_NAME ); + TestLog FILE_LOG = getLog( output, FILE_LOG_NAME ); + TestLog SUITE_LOG = getLog( output, SUITE_LOG_NAME ); + TestLog CASE_LOG = getLog( output, CASE_LOG_NAME ); + + if ( DEBUG ) { + TestLog DEBUG_LOG = getLog( output, DEBUG_LOG_NAME ); + } + + return; + } + + public void writeLogHeaders( File output ) { + String header = ""+ + "" + + "" + + ( EXECUTABLE == null + ? "" + + "" + : "" + ) + + ""+ + ""+ + ""+ + ""+ + ""+ + "
Test Driver " + this.getClass().toString() +"
Output Directory " + OUTPUT_DIRECTORY +"
OptLevel " + OPT_LEVEL +"
DebugLevel " + DEBUG_LEVEL+"
Executable " + EXECUTABLE +"
Java Version " + System.getProperty("java.vendor")+ + " "+ System.getProperty( "java.version" ) +"
Test File Directory " + TEST_DIRECTORY +"
Helper Functions " + HELPER_FUNCTIONS +"
Free Memory " + FREE_MEMORY +"
Total JVM Memory " + TOTAL_MEMORY +"
"; + + getLog( OUTPUT_DIRECTORY, SUITE_LOG_NAME ).writeLine( header ); + getLog( OUTPUT_DIRECTORY, CASE_LOG_NAME ).writeLine( header ); + getLog( OUTPUT_DIRECTORY, FILE_LOG_NAME ).writeLine( header ); + getLog( OUTPUT_DIRECTORY, SUMMARY_LOG_NAME ).writeLine( header ); + + getLog( OUTPUT_DIRECTORY, SUMMARY_LOG_NAME ).writeLine( + "" + + "" + + "" + + "" + + "
Suite" + + " Files" + + " Cases" + + " Passed" + + " Failed" + + " Result" + + "
#" + + " %" + + " #" + + " %" + + "
" ); + return; + } + + /** + * For each subdirectory of the main test directory, create a new + * TestSuite object. + */ + + public Vector getSuites( String[] files ) { + Vector suites = new Vector(); + + for ( int i = 0; i < files.length; i++ ) { + String filename = stripDoubleSlashes( TEST_DIRECTORY + + File.separator + files[i] ); + File fileobject = new File( filename ); + + if ( fileobject.isDirectory() ) { + TestSuite s = new TestSuite( fileobject.getName(), + filename ); + suites.addElement( s ); + } + } + + return suites; + } + /** + * If two slashes in a row are found, one slash is stripped out. + * Mac client has trouble if we don't do this. + * xxx this doesn't work and needs to be fixed. + */ + public static String stripDoubleSlashes( String string ) { + StringBuffer buffer = new StringBuffer(); + for ( int letter = 0; letter < string.length(); letter++ ) { + char current_char = string.charAt(letter); + + if ( current_char != File.separatorChar ) { + buffer.append(current_char); + } else { + while ( string.charAt(++letter) == + File.separatorChar ) + { + ; + } + // only add one slash + buffer.append( File.separatorChar ); + --letter; + } + + } + /* + if ((new Character(string.charAt(letter))).toString().equals("/")){ + if (!(new Character( + string.charAt(letter+1))).toString().equals("/")) + { + // only got one, leave it alone + buffer.append( string.charAt( letter ) ); + } + } else { + buffer.append( string.charAt( letter ) ); + } + */ + + + return buffer.toString(); + } + + /** + * For each test file in the suite directory, create a TestFile object. + * + */ + + public void getCases( TestSuite suite ) { + enablePrivileges(); + + File dir = new File ( suite.filePath ); + String[] files = dir.list(); + + for ( int i = 0; i < files.length; i++ ) { + TestFile item = new TestFile( files[i], + suite.filePath + File.separator+ files[i] ); + + if ( item.isFile() + && (item.getName().toLowerCase()).endsWith(getSuffix()) + && (!item.isDirectory()) ) { + suite.addElement(item); + p( item +"" ); + } + } + } + /** + * Subclasses should override this method to iterate through all TestFiles + * in the TestSuite, create a new TestEnvironment, run the test, and close + * the TestEnvironment. + * + * For examples, + * @see com.netscape.javascript.qa.drivers.RhinoDrv and + * @see com.netscape.javascript.qa.drivers.RefDrv + */ + public synchronized void executeSuite( TestSuite suite ) { + } + + /** + * If the environment uses a Security Manager and requires privileges to + * access system properties, override this method to enable privileges. + * The default method does nothing. + * + */ + + public static void enablePrivileges() { + } + + /* + * Begin functions that write to logs + * + * These methods are static so that LiveConnectTest objects can call them + * directly. + * + */ + + /** + * Write the suite result to the Tinderbox log. + * + * + * XXX need machine, branch, startTime, endTime + */ + public void writeTinderboxHeader( String executable ) { + String dottedLine = + "--------------------------------------------------------------"; + + String product = ( executable == null ) ? "ns/js/rhino" : "ns/js/ref"; + String osInfo = System.getProperty( "os.name" ) +" " + + System.getProperty( "os.arch" ) +" " + + System.getProperty( "os.version" ); + String javaInfo=System.getProperty( "java.vendor" ) +" "+ + System.getProperty( "java.version" ); + + // Create the log string; + + System.out.println( dottedLine ); + System.out.println( "Product " + product ); +// System.out.println( "Machine " + machine ); + System.out.println( "Operating System " + osInfo ); + System.out.println( "Java Version " + javaInfo); + System.out.println( "Free Memory " + FREE_MEMORY ); + System.out.println( "Total JVM Memory " + TOTAL_MEMORY ); + + System.out.println( "Test Driver " + this.getClass().getName()); + System.out.println( "Output Directory " + OUTPUT_DIRECTORY ); + System.out.println( "Path to Executable " + EXECUTABLE ); + + if ( product.equals( "ns/js/rhino" ) ){ + System.out.println( "Optimization Level " + OPT_LEVEL ); + System.out.println( "Debug level " + DEBUG_LEVEL ); + } + + + System.out.println( "Test Directory " + TEST_DIRECTORY ); + System.out.println( dottedLine ); + } + + + public void writeTinderboxSuiteName( TestSuite suite ) { + System.out.println( "Suite " + suite.name ); + } + + public void writeTinderboxSuiteResult( TestSuite suite ) { + String dottedLine = + "--------------------------------------------------------------"; + + System.out.println( "Result " + ( suite.passed + ? "PASSED" : "FAILED")); + + if ( ! suite.passed ) { + System.out.println( "Failed Files " ); + for ( int i = 0; i < suite.size(); i++ ) { + TestFile file = (TestFile) suite.elementAt(i); + if ( ! file.passed ) { + System.out.println( file.name + + (file.bugnumber.equals("") ? "" : + " http://scopus.mcom.com/bugsplat/show_bug.cgi?id="+ + file.bugnumber +" ")); + } + } + } + + System.out.println( dottedLine ); + } + + /** + * Write an HTML-formatted string to SUITE_LOG. + */ + public static void writeSuiteResult( TestSuite suite, File output ) { + if ( ! (suite.size() > 0) ) { + return; + } + + String buffer = ""; + buffer += ( "" + + ( suite.passed + ? "passed" + : "FAILED" + ) + + " " + + ""+ + suite.name +"" ); + + if ( ! suite.passed ) { + for ( int i = 0; i < suite.size(); i++ ) { + TestFile file = (TestFile) suite.elementAt(i); + if ( ! file.passed ) { + buffer += ( " " + + "" + + file.name + "" ); + + if ( ! file.bugnumber.equals("") ) { + buffer += ( " "+ + "("+file.bugnumber+")" ); + } + } + } + } + + buffer += ( "
" ); + + getLog( output, SUITE_LOG_NAME).writeLine( buffer.toString() ); + } + + /** + * Write an HTML-formatted string to the SUMMARY_LOG that looks like + * this: + *
+     *  Suite       Number of       Number of       Passed      Failed      Result
+     *  Name        Files           Cases           #  %        #    %
+     *
+     *  
+ */ + public static void writeSuiteSummary( TestSuite suite, File output ) { + if ( ! (suite.size() > 0) ) { + return; + } + + String buffer = ""; + p( "total :"+ suite.totalCases ); + p("passed :"+ suite.casesPassed ); + p("failed :"+ suite.casesFailed ); + + + double percentPassed = Math.round((double) suite.casesPassed / + (double) suite.totalCases * 10000)/100 ; + double percentFailed = Math.round((double) suite.casesFailed / + (double) suite.totalCases * 10000)/100 ; + + buffer += ( "" ); + buffer += ( "
" + + suite.name ); + + buffer += ( "" + suite.size() + + "" + suite.totalCases + + "" + suite.casesPassed + + "" + percentPassed + + "" + suite.casesFailed + + "" + percentFailed + + "" + + ( ( suite.passed == true ) + ? "PASSED" + : "FAILED" + ) + "
" ); + + for ( int i = 0; i < suite.size(); i++ ) { + TestFile file= ((TestFile) suite.elementAt(i)); + + double pPassed = 0; + double pFailed = 0; + + if ( file.totalCases > 0 ) { + pPassed = (Math.round((double) file.casesPassed / + (double) file.totalCases * 10000))/100 ; + pFailed = (Math.round((double) file.casesFailed / + (double) file.totalCases * 10000))/100 ; + } + + buffer += ( "" + + "" + + "
" + + "" + file.name + "" + + "" + file.totalCases + + "" + file.casesPassed + + "" + pPassed + + "" + file.casesFailed + + "" + pFailed + + "" + + ( ( file.passed == true ) + ? "PASSED" + : "FAILED" + ) + + ( ( file.reason.equals("") ) + ? "" + : ": "+ file.reason + ) + + ( ( file.exception.equals("") ) + ? "" + : ":
"+ file.exception + ) + + "
" ); + } + + getLog( output, SUMMARY_LOG_NAME ).writeLine( buffer.toString() ); + } + + /** + * Write the result of the current file to the FILE_LOG. + * If the file threw an exception, print the exception. + * + */ + public static void writeFileResult( TestFile file, TestSuite suite, File output ) { + String suitename = ( suite == null ) ? "" : suite.name; + + if ( !file.passed ) { + String buffer = ""; + + buffer += ( "PASSED " + : "#dd0000>FAILED " ) + + "" + + suitename+" "+file.name + " " + + file.exception + "\n" ); + + if ( ! file.bugnumber.equals("") ) { + buffer += ( " "+ + "("+file.bugnumber+")" ); + } + getLog( output, FILE_LOG_NAME ).writeLine( buffer.toString() ); + + } + } + + /** + * Read the contents of a file into a string. + */ + public static String readFile( String filePath ) { + File jsFile = new File( filePath ); + + int length = new Long( jsFile.length()).intValue(); + byte[] b = new byte[length]; + StringBuffer contents = new StringBuffer(); + + try { + FileInputStream fis = new FileInputStream( jsFile ); + int read = fis.read( b ); + contents.append( new String( b ) ); + } catch ( Exception e ) { + p( e.toString() ); + } + return ( contents.toString() ); + } + /** + Test Case Management System (TCMS) requires the following + information: + (MachineID), -pass- or *FAIL*, TestFileName/Beaker, + TestFileName,Date Run in MM/DD/YY, Start Time HH:MM:SS, + End Time HH:MM:SS, ExpectedResults String + (quite often null), Actual Result String, Reason For Failure + + Tests can provide this information. we expected it to be + in an object called "TestCase" with the following structure: + +
+        function TestCase( passed, name, expect, actual, reason ) {
+            this.passed = passed;
+            this.name   = "Description of the Test Case";
+            this.expect = ( theExpectedResult );
+            this.actual = ( theActualResult );
+            this.reason = ( reasonForFailure );
+        }
+        
+ + we will generate machineID, pass/fail, date run, start time, + end time. + + If TCMS == false, omit unnecessary log id. + + */ + public static void writeCaseResults( TestFile file, TestSuite suite, + File output ) + { + suite.totalCases += file.totalCases; + + String[] SYSTEM = getSystemInformation(); + + String buffer = ""; + + for ( int i = 0; i < file.caseVector.size(); i++ ) { + TestCase tcase = (TestCase) (file.caseVector.elementAt(i)); + + // format and write test case results to CASE_LOG + if ( !tcase.passed.equals("true")) { + if ( !file.passed ) { + buffer += (""); + buffer += (""); + buffer += ( "(" + SYSTEM[0] + "), " ); + } + } + + if ( tcase.passed.equals("true")) { + if (!file.passed) + buffer += ( "-pass-, " ); + suite.casesPassed += 1; + file.casesPassed += 1; + } else { + if (!file.passed) + buffer += ( "*FAIL*, "); + suite.casesFailed += 1; + file.casesFailed += 1; + } + + if ( TCMS ) { + buffer += ( tcase.name + "-" + tcase.description + "/Beaker, " + + tcase.name + "-" + tcase.description + ", " + + getCurrentDate("/") + ", " + + file.startTime + ", " + + file.endTime + ", " + + tcase.expect +", " + + tcase.actual +", " + + tcase.reason + "\n" ); + } else { + buffer += ( tcase.name +","+ + tcase.description +","+ + tcase.expect +","+ + tcase.actual +","+ + tcase.reason +"\n" ); + } + + if (!tcase.passed.equals("true")) { + buffer += ("
\n"); + getLog( output, CASE_LOG_NAME ).writeLine( buffer.toString() ); + } else { + buffer = ""; + } + } + } + + /** + * Short version of writing test case results to the CASE_LOG, used by + * LiveConnecTest subclasses. + * + * @param cases vector of testcases whose results should be written + * to the CASE_LOG. LiveConnectTest sends a vector of failed TestCase + * objects. + * @param classname name of the LiveConnectTest class + * @param output directory in which output is written. + * + * @see + * com.netscape.javascript.qa.liveconnect.LiveConnectTest#writeResultsToCaseLog + * + */ + + public static void writeCaseResults( TestFile file, String classname, + File output ) + { + String[] system = getSystemInformation(); + String buffer = ""; + + for ( int i = 0; i < file.caseVector.size(); i++ ) { + TestCase tcase = (TestCase) (file.caseVector.elementAt(i)); + if ( tcase.passed.equals("true")) { +// buffer += ( "-pass-, " ); + } else { + buffer += (""); + buffer += ( "(" + system[0] + "), " ); + + buffer += ( "*FAIL*, "); + buffer += ( tcase.name +","+ + tcase.description +","+ + tcase.expect +","+ + tcase.actual +","+ + tcase.reason +"\n" ); + buffer += ("
\n"); + getLog( output, CASE_LOG_NAME ).writeLine( buffer.toString() ); + } + } + } + /** + Write system information and current date to the SUMMARY_LOG, + FILE_LOG, and SUITE_LOG. + + XXX need to fix this to output all test information. + */ + public static void writeDateToLogs( String separator, File output ) { + Date today = new Date(); + String[] SYSTEM = getSystemInformation(); + +// long NEW_FREE_MEMORY = RUNTIME.freeMemory(); +// long NEW_TOTAL_MEMORY = RUNTIME.totalMemory(); + + String string = ""+ +// "Free Memory " + NEW_FREE_MEMORY + "\n
"+ +// "Total Memory " + NEW_TOTAL_MEMORY +"\n
"+ +// "Free Leaked " + FREE_MEMORY - NEW_FREE_MEMORY +"\n
"+ +// "Total Leaked " + TOTAL_MEMORY-NEW_TOTAL_MEMORY +"\n
"+ + "
"+ + separator + SYSTEM[0] +" "+ SYSTEM[1] +" "+ SYSTEM[2] +" "+ + today.toString(); + + getLog( output, SUMMARY_LOG_NAME ).writeLine( string ); + getLog( output, FILE_LOG_NAME).writeLine( string ); + getLog( output, SUITE_LOG_NAME).writeLine( string ); + if ( !TCMS ) { + getLog( output, CASE_LOG_NAME ).writeLine( string ); + } + } + + /** + * Convenience methods. + */ + + public static void p( String s ) { + if ( !TestDriver.TINDERBOX ) { + System.out.println( s ); + } + } + public static void debug (String s ) { + if ( DEBUG && !TestDriver.TINDERBOX ) + System.err.println( s ); + } + /** + From the current Date, return a string in the format "DD?MM?YY", + where "/" is specified by the separator argument. + */ + public static String getCurrentDate( String separator ) { + Date today = new Date(); + String date = (today.getDate() < 10) + ? "0" + String.valueOf( today.getDate() ) + : String.valueOf( today.getDate() ); + String month = (today.getMonth() + 1 < 10 ) + ? "0" + String.valueOf( (today.getMonth() +1) ) + : String.valueOf( today.getMonth() + 1 ); + String year = String.valueOf( today.getYear() ); + + return ( month + separator + date + separator + year ); + } + /** + From the current time, return a string in the format "HH:MM:SS" + */ + + public static String getCurrentTime() { + Date now = new Date(); + String hours = ( now.getHours() < 10 ) + ? "0" + String.valueOf( now.getHours() ) + : String.valueOf( now.getHours() ); + + String minutes = ( now.getMinutes() < 10 ) + ? "0" + String.valueOf( now.getMinutes() ) + : String.valueOf( now.getMinutes() ); + + String seconds = ( now.getSeconds() < 10 ) + ? "0" + String.valueOf( now.getSeconds() ) + : String.valueOf( now.getSeconds() ); + + String time = hours + ":" + minutes + ":" + seconds; + + return ( time ); + } + public String getSuffix() { + return SUFFIX; + } + public void setSuffix(String s) { + SUFFIX = s; + } + /** + * Temporary stop this thread for 5 seconds. + * + */ + public boolean sleep(int ms) { + try { + THREAD.sleep( 5000 ); + } catch ( Exception e ) { + p( "sleep failed: " + e ); + return false; + } + return true; + } + + /** + * Implementations need to override this method, which should call + * its own constructor, passing the args object as an argument. + */ + + + /** + * Process options should parse the ARGS object. + * + * return true if the driver should continue. return false if the driver + * should not continue. + * + */ + + public boolean processOptions() { + return false; + } + public static void main ( String[] args ) { + TestDriver d = new TestDriver( args ); + d.start(); + } + + public static final String SUMMARY_LOG_NAME = "summ.html"; + public static final String CASE_LOG_NAME = "case.html"; + public static final String FILE_LOG_NAME = "file.html"; + public static final String SUITE_LOG_NAME = "suite.html"; + public static final String DEBUG_LOG_NAME = "debug.html"; + public static final String TERMINATOR = "
\n"; + + } + diff --git a/js/tests/src/com/netscape/javascript/qa/drivers/TestEnvironment.java b/js/tests/src/com/netscape/javascript/qa/drivers/TestEnvironment.java new file mode 100644 index 00000000000..fae9481f4a3 --- /dev/null +++ b/js/tests/src/com/netscape/javascript/qa/drivers/TestEnvironment.java @@ -0,0 +1,62 @@ +/* -*- Mode: java; tab-width: 8 -*- + * Copyright © 1997, 1998 Netscape Communications Corporation, + * All Rights Reserved. + */ + +package com.netscape.javascript.qa.drivers; + +/** + * TestEnvironment creates the JavaScript environment in which the program in + * the TestFile is evaluated. It expects the test result to be a JavaScript + * array of JavaScript TestCase objects. TestEnvironment creates a + * com.netscape.javascript.qa.drivers.TestCase object for each TestCase it + * finds, and populates the TestCase, TestFile, and TestSuite object + * properties. + * + * @see com.netscape.javascript.qa.drivers.TestDriver + * @author christine@netscape.com + * + */ +public interface TestEnvironment { + /** + * Pass the JavaScript program to the JavaScript environment. + */ + + public void runTest(); + + /** + * Create a new JavaScript context in which to evaluate a JavaScript + * program. + * + * @return the JavaScript context + * + */ + public Object createContext(); + + /** + * Given a filename, evaluate the file's contents as a JavaScript + * program. + * + * @return the return value of the JavaScript program. If the test throws + * a Java exception or JavaScript runtime or compilation error, return the + * string value of the error message. + */ + public Object executeTestFile(); + + /** + * Evaluate the result of the JavaScript program. Attempt to get the + * JavaScript Array of TestCase objects. For each TestCase object + * found, create a com.netscape.javascript.qa.drivers.TestCase object + * and populate its fields. + * + * @return true if the the result could be parsed successfully; false + * otherwise. + */ + + public boolean parseResult(); + + /** + * Close the context. Destroy the JavaScript environment. + */ + public void close(); +} \ No newline at end of file diff --git a/js/tests/src/com/netscape/javascript/qa/drivers/TestFile.java b/js/tests/src/com/netscape/javascript/qa/drivers/TestFile.java new file mode 100644 index 00000000000..0cf2120b081 --- /dev/null +++ b/js/tests/src/com/netscape/javascript/qa/drivers/TestFile.java @@ -0,0 +1,65 @@ +/* -*- Mode: java; tab-width: 8 -*- + * Copyright © 1997, 1998 Netscape Communications Corporation, + * All Rights Reserved. + */ + +package com.netscape.javascript.qa.drivers; + +import java.io.*; +import java.util.*; + +/** + * For each file found in a test suite directory, the TestDriver creates a + * TestFile object. This object has no methods; it only stores information + * about the program in the file it represents. TestFile fields are populated + * by the TestEnvironment when the program in the TestFile is executed. + * + * @see com.netscape.javascript.qa.drivers.TestDriver + * @see com.netscape.javascript.qa.drivers.TestEnvironment + * + * @author christine@netscape.com + */ + +public class TestFile extends File { + public String description; + public String name; + public String filePath; + public boolean passed; + public boolean completed; + public String startTime; + public String endTime; + public String reason; + public String program; + public int totalCases; + public int casesPassed; + public int casesFailed; + public Vector caseVector; + public String exception; + public String bugnumber; + + /** + * Create a new TestFile. + * + * @param name name of this test file + * @param filePath full path to this file + */ + + public TestFile( String name, String filePath ) { + super( filePath ); + + this.name = name; + this.filePath = filePath; + this.passed = true; + this.completed = false; + this.startTime = "00:00:00"; + this.endTime = "00:00:00"; + this.reason = ""; + this.program = ""; + this.totalCases = 0; + this.casesPassed = 0; + this.casesFailed = 0; + this.caseVector = new Vector(); + this.exception = ""; + this.bugnumber = ""; + } +} \ No newline at end of file diff --git a/js/tests/src/com/netscape/javascript/qa/drivers/TestLog.java b/js/tests/src/com/netscape/javascript/qa/drivers/TestLog.java new file mode 100644 index 00000000000..12764d1641e --- /dev/null +++ b/js/tests/src/com/netscape/javascript/qa/drivers/TestLog.java @@ -0,0 +1,84 @@ +/* -*- Mode: java; tab-width: 8 -*- + * Copyright © 1997, 1998 Netscape Communications Corporation, + * All Rights Reserved. + */ + +package com.netscape.javascript.qa.drivers; + +//import netscape.security.PrivilegeManager; +import java.io.*; + +/** + * Class that writes and appends test result information to a file. + * + * @author christine@netscape.com + * + */ +public class TestLog { + private String name; + private ByteArrayOutputStream outputStream; + private PrintStream printStream; + private String terminator; + + /** + * Create a new TestLog and open associated streams. + * + * @param name name of the log file + * @param terminator string that will be appended to the end of each line + * + * + */ + public TestLog ( String name, String terminator ) { + this.name = name; + this.terminator = terminator; + + openLog(); + } + + /** + * Write a string to the end TestLog file. + */ + public void writeLine( String string ) { + if ( printStream != null ) { + printStream.println( string + terminator ); + try { + RandomAccessFile raf = new RandomAccessFile( name, "rw" ); + raf.seek( raf.length() ); + raf.write( outputStream.toByteArray() ); + raf.close(); + outputStream.reset(); + } catch ( Exception e ) { + System.out.println( "Exception writing to "+ name +".writeLine():"+ e ); + } + } + } + + /** + * Override if privileges are required to write to file system. + * The default implemenation does nothing. + */ + public void enablePrivileges() { + return; + } + + /** + * Close print stream associated with the TestLog file. + */ + public void closeLog() { + if ( printStream != null ) { + printStream.close(); + } + } + /** + * Create streams associated with this TestLog file. + */ + public void openLog() { + enablePrivileges(); + this.outputStream = new ByteArrayOutputStream(); + this.printStream = new PrintStream( this.outputStream ); + } + + public String toString() { + return this.name; + } +} \ No newline at end of file diff --git a/js/tests/src/com/netscape/javascript/qa/drivers/TestSuite.java b/js/tests/src/com/netscape/javascript/qa/drivers/TestSuite.java new file mode 100644 index 00000000000..6c909b387a7 --- /dev/null +++ b/js/tests/src/com/netscape/javascript/qa/drivers/TestSuite.java @@ -0,0 +1,47 @@ +/* -*- Mode: java; tab-width: 8 -*- + * Copyright © 1997, 1998 Netscape Communications Corporation, + * All Rights Reserved. + */ + +package com.netscape.javascript.qa.drivers; + +import java.io.*; +import java.util.*; + +/** + * For each directory that the TestDriver finds, the TestDriver creates a + * TestSuite object. The TestDriver executes the JavaScript tests it finds + * in that directory, and updates the TestSuite object properties, maintaing + * the total number of test cases, and the number of test cases that have + * failed. + * + * @see com.netscape.javascript.qa.drivers.TestDriver + * @see com.netscape.javascript.qa.drivers.TestEnvironment + * + * @author christine@netscape.com + */ + +public class TestSuite extends Vector { + public String name; + public String filePath; + public boolean passed; + public int totalCases; + public int casesPassed; + public int casesFailed; + + /** + * Create a new TestSuite object. + * + * @param name name of the TestSuite + * @param filePath full path to TestSuite directory + */ + + public TestSuite( String name, String filePath ) { + this.name = name; + this.filePath = filePath; + this.passed = true; + this.totalCases = 0; + this.casesPassed = 0; + this.casesFailed = 0; + } +} \ No newline at end of file