* runtests2.pl was renamed to jsDriver.pl

jsDriver.pl now supports multiple lists to be specified in the -l argument,
and directory names as well.  Directory names can also be used in list files.
'Negative' lists are supported as well.  They consist of a list of tests to skip, and are of the same format as the regular lists.

* README-jsDriver.html
  man-like html page describing how to use jsDriver.pl
This commit is contained in:
rginda%netscape.com 1999-12-05 02:15:22 +00:00
parent b1ccfbf911
commit 7127cadec4
3 changed files with 1233 additions and 801 deletions

View File

@ -0,0 +1,305 @@
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
<html>
<head>
<title>jsDriver.pl</title>
<style>
dt {
font-family: Courier;
}
</style>
</head>
<body bgcolor="white">
<h1 align="right">jsDriver.pl</h1>
<dl>
<dt><b>NAME</b></dt>
<dd>
jsDriver.pl - execute JavaScript programs in various shells in
batch or single mode, reporting on failures encountered.
<br>
<br>
<dt><b>SYNOPSIS</b></dt>
<dd>
<code>
<b>jsDriver.pl</b> [-hkt] [-b BUGURL] [-c CLASSPATH] [-f OUTFILE]
[-j JAVAPATH] [-l TESTLIST ...] [-L NEGLIST ...] [-p TESTPATH]
[-s SHELLPATH] [-u LXRURL] [--help] [--confail] [--trace]
[--classpath=CLASSPATH] [--file=OUTFILE] [--javapath=JAVAPATH]
[--list=TESTLIST] [--neglist=TESTLIST] [--testpath=TESTPATH]
[--shellpath=SHELLPATH] [--lxrurl=LXRURL] {-e ENGINETYPE |
--engine=ENGINETYPE}
</code>
<br>
<br>
<dt><b>DESCRIPTION</b></dt>
<dd>
<b>jsDriver.pl</b> is normally used to run a series of tests against
one of the JavaScript shells. These tests are expected to be laid out
in a directory structure exactly two levels deep. The first level
represents a &quot;Test Suite&quot; and generally marks a broad
category such as <i>ECMA Level 1</i> or <i>Live Connect 3</i>. The next
level represents a &quot;Suite Category&quot; and divides tests
inside a suite into smaller categories, such as <i>Execution Contexts</i>
or <i>Lexical Rules</i>. Testcases reside under the &quot;Suite
Categories&quot; as normal JavaScript (*.js) files. If a file named
shell.js exists in either the suite path (the parent directory of the
&quot;Test Suites&quot;) or the indiviual &quot;Suite Category&quot;
directory, it is loaded into the shell before the testcase. You can
use this to declare functions and variables common to an entire suite
or category.
<p>
Testcases can report failures back to <b>jsDriver.pl</b> in one of
two ways. The most common is to write a line of text containing
the word <code>FAILED!</code> to <b>STDOUT</b> or <b>STDERR</b>.
When the engine encounters a matching line, the test is marked as
failed, and any line containing <code>FAILED!</code> is displayed in
the failure report. The second way a test case can report failure is
to return an unexpected exit code. By default, <b>jsDriver.pl</b>
expects all test cases to return exit code 0, although a test
can output a line containing <code>EXPECT EXIT <i>n</i></code> where
<i>n</i> is the exit code the driver should expect to see. Testcases
can return a nonzero exit code by calling the shell function
<code>exit(<i>n</i>)</code> where <code><i>n</i></code> is the
code to exit with. Also, the various JavaScript shells report
non-zero exit codes under the following conditions:
<center>
<table border="1">
<tr>
<th>Reason</th>
<th>Exit Code</th>
</tr>
<tr>
<td>
Engine initialization failure.
</td>
<td>
1
</td>
</tr>
<tr>
<td>
Invalid argument on command line.
</td>
<td>
2
</td>
</tr>
<tr>
<td>
Runtime error (uncaught exception) encountered.
</td>
<td>
3
</td>
</tr>
<tr>
<td>
File argument specified on command line not found.
</td>
<td>
4
</td>
</tr>
<tr>
<td>
Reserverd for future use.
</td>
<td>
5-9
</td>
</tr>
</table>
</center>
<br>
<br>
<dt><b>OPTIONS</b></dt>
<dd>
<dl>
<dt><b>-b URL, --bugurl=URL</b></dt>
<dd>
Bugzilla URL. When a testcase writes a line in the format
<code>BUGNUMBER <i>n</i></code> to <b>STDOUT</b> or <b>STDERR</b>,
<b>jsDriver.pl</b> interprets <code><i>n</i></code> as a bugnumber
in the <a href="http://bugzilla.mozilla.org">BugZilla</a> bug
tracking system. In the event that a testcase which has specified
a bugnumber in the manner fails, a hyperlink to the BugZilla database
will be included in the output by prefixing the bugnumber with the
URL specified here. By default, URL is assumed to be
&quot;http://bugzilla.mozilla.org/show_bug.cgi?id=&quot;.
<br>
<br>
<a name="classpath"></a>
<dt><b>-c PATH, --classpath=PATH</b></dt>
<dd>
Classpath to pass the the Java Virtual Machine. When running tests
against the <b>Rhino</b> engine, PATH will be passed in as the value
to an argument named &quot;-classpath&quot;. If your particular JVM
does not support this option, it is recommended you specify your
class path via an environment setting. Refer to your JVM
documentation for more details about CLASSPATH.
<br>
<br>
<dt><b>-e TYPE, --engine=TYPE</b></dt>
<dd>
Required. Type of engine to run the tests against. TYPE can be one
of the following values:
<center>
<table border="1">
<tr>
<th>TYPE</th>
<th>Engine</th>
</tr>
<tr>
<td>lcopt</td>
<td>LiveConnect, optimized</td>
</tr>
<tr>
<td>lcdebug</td>
<td>LiveConnect, debug</td>
</tr>
<tr>
<td>rhino</td>
<td>Rhino</td>
</tr>
<tr>
<td>smopt</td>
<td>Spider-Monkey, optimized</td>
</tr>
<tr>
<td>smdebug</td>
<td>Spider-Monkey, debug</td>
</tr>
<tr>
<td>xpcshell</td>
<td>XPConnect shell</td>
</tr>
</table>
</center>
<br>
<br>
<dt><b>-f FILE, --file=FILE</b></dt>
<dd>
Generate html output to the HTML file named by FILE. By default,
a filename will be generated using a combination of the engine type
and a date/time stamp, in the format:
results-&lt;engine-type&gt;-&lt;date-stamp&gt;.html
<br>
<br>
<dt><b>-h, --help</b></dt>
<dd>
Prints usage information.
<br>
<br>
<dt><b>-j PATH, --javapath=PATH</b></dt>
<dd>
Set the location of the Java Virtual Machine to use when running
tests against the <b>Rhino</b> engine. This can be used to test
against multiple JVMs on the same system.
<br>
<br>
<dt><b>-k, --confail</b></dt>
<dd>
Log failures to the console. This will show any failures, as they
occur, on <b>STDERR</b> in addition to creating the HTML results
file. This can be useful for times when it may be
counter-productive to load an HTML version of the results, or as
input to a larger test driver which may execute <b>jsDriver.pl</b>
with a variety of options.
<br>
<br>
<dt><b>-l FILE ..., --list=FILE ...</b></dt>
<dd>
Specify a list of tests to execute. FILE can be a plain text file
containing a list of testcases to execute, a subdirectory
in which to
<a href="http://www.instantweb.com/~foldoc/foldoc.cgi?query=grovel">
grovel (2)</a>
for tests, or a single testcase to execute. Any number of FILE
specifiers may follow this option. The driver uses the fact that a
valid testcase should be a file ending in .js to make the distinction
between a file containg a list of tests and an actual testcase.
<br>
<br>
<dt><b>-L FILE ..., --neglist=FILE ...</b></dt>
<dd>
Specify a list of tests to skip. FILE has the same meaning as in
the <b>-l</b> option. This option is evaluated after
<b>all</b> <b>-l</b> and <b>--list</b> options, allowing a user
to subtract a single testcase, a directory of testcases, or a
collection of unrelated testcases from the exection list.
<br>
<br>
<dt><b>-p PATH, --testpath=PATH</b></dt>
<dd>
Directory holding the &quot;Test Suite&quot; subdirectories. By
default this is ./
<br>
<br>
<dt><b>-s PATH, --shellpath=PATH</b></dt>
<dd>
Directory holding the JavaScript shell. This can be used to override
the automatic shell location <b>jsDriver.pl</b> performs based on
you OS and engine type. <b>Do not</b> include the name of the
executable, only the path. In <b>Rhino</b>, this path will be
appended to your <a href="#classpath">CLASSPATH</a>. For the
<b>SpiderMonkey</b> shells, this value defaults to
../src/&lt;Platform-and-buildtype-specific-directory&gt;, for the
<b>LiveConnect</b> shells,
../src/liveconnect/src/&lt;Platform-and-buildtype-specific-directory&gt;
and for the <b>xpcshell</b> the default is the value of your
<code>MOZILLA_FIVE_HOME</code> environment variable. There is no
default (as it is usually not needed) for the <b>Rhino</b> shell.
<br>
<br>
<dt><b>-t, --trace</b></dt>
<dd>
Trace execution of <b>jsDriver.pl</b>. This option is primarily
used for debugging of the script itself, but if you are interested in
seeing the actual command being run, or generally like gobs of
useless information, you may find it entertaining.
<br>
<br>
<dt><b>-u URL, --lxrurl=URL</b></dt>
<dd>
Failures listed in the HTML results will be hyperlinked to the
lxr source available online by prefixing the test path and
name with this URL. By default, URL is
http://lxr.mozilla.org/mozilla/source/js/tests/
<br>
<br>
</dl>
<dt><b>BUGS</b></dt>
<dd>
This script needs to be modified to work with MacPerl<br>
At the time of this writing (12/02/99), the LiveConnect shell does not
return proper exit codes. This is expected to be changed soon.<br>
<dt><b>SEE ALSO</b></dt>
<dd>
mklistpage.pl,
<a href="http://www.mozilla.org/js/">http://www.mozilla.org/js/</a>
<br>
<br>
<dt><b>BUGS</b></dt>
<dd>
This script needs to be modified to work with MacPerl<br>
At the time of this writing (12/02/99), the LiveConnect shell does not
return proper exit codes. This is expected to be changed soon.<br>
</dl>
<hr>
<address><a href="mailto:rginda@netscape.com">Robert Ginda</a></address>
<!-- Created: Thu Dec 2 19:08:05 PST 1999 -->
<!-- hhmts start -->
Last modified: Thu Dec 2 19:08:05 PST 1999
<!-- hhmts end -->
</body>
</html>

927
js/tests/jsDriver.pl Executable file
View File

@ -0,0 +1,927 @@
#!/usr/bin/perl
#
# The contents of this file are subject to the Netscape Public
# License Version 1.1 (the "License"); you may not use this file
# except in compliance with the License. You may obtain a copy of
# the License at http://www.mozilla.org/NPL/
#
# Software distributed under the License is distributed on an "AS
# IS" basis, WITHOUT WARRANTY OF ANY KIND, either express oqr
# implied. See the License for the specific language governing
# rights and limitations under the License.
#
# The Original Code is JavaScript Core Tests.
#
# The Initial Developer of the Original Code is Netscape
# Communications Corporation. Portions created by Netscape are
# Copyright (C) 1997-1999 Netscape Communications Corporation. All
# Rights Reserved.
#
# Alternatively, the contents of this file may be used under the
# terms of the GNU Public License (the "GPL"), in which case the
# provisions of the GPL are applicable instead of those above.
# If you wish to allow use of your version of this file only
# under the terms of the GPL and not to allow others to use your
# version of this file under the NPL, indicate your decision by
# deleting the provisions above and replace them with the notice
# and other provisions required by the GPL. If you do not delete
# the provisions above, a recipient may use your version of this
# file under either the NPL or the GPL.
#
# Contributers:
# Robert Ginda
#
# Second cut at runtests.pl script originally by
# Christine Begle (cbegle@netscape.com)
# Branched 11/01/99
#
use Getopt::Mixed "nextOption";
# command line option defaults
local $opt_classpath = "";
local $opt_engine_type = "";
local $opt_output_file = "";
local @opt_test_list_files;
local @opt_neg_list_files;
local $opt_suite_path = "./";
local $opt_shell_path = "";
local $opt_java_path = "";
local $opt_bug_url = "http://bugzilla.mozilla.org/show_bug.cgi?id=";
local $opt_trace = 1;
local $opt_console_failures = 0;
local $opt_lxr_url = "http://lxr.mozilla.org/mozilla/source/js/tests/";
# command line option definition
local $options = "b=s bugurl>b c=s classpath>c e=s engine>e f=s file>f " .
"h help>h i j=s javapath>j k confail>k l=s list>l L=s neglist>L " .
"p=s testpath>p s=s shellpath>s t trace>t u=s lxrurl>u";
&parse_args;
local $os_type = &get_os_type;
local $engine_command = &get_engine_command;
local $user_exit = 0;
local $html = "";
local @failed_tests;
local $failures_reported = 0;
local $tests_completed = 0;
local @test_list = &get_test_list;
local $exec_time_string;
local $start_time = time;
if ($os_type ne "WIN") {
$SIG{INT} = 'int_handler';
}
if ($#test_list == -1) {
die ("Nothing to test.\n");
}
&execute_tests (@test_list);
local $exec_time = (time - $start_time);
local $exec_mins = int($exec_time / 60);
local $exec_secs = ($exec_time % 60);
if ($exec_mins > 0) {
$exec_time_string = "$exec_mins minutes, $exec_secs seconds";
} else {
$exec_time_string = "$exec_secs seconds";
}
&write_results;
#End.
sub execute_tests {
local (@test_list) = @_;
local $test, $shell_command, $line, @output;
local $file_param = " -f ";
local $last_suite, $last_test_dir;
local $failure_lines;
&status ("Executing " . ($#test_list + 1) . " test(s).");
foreach $test (@test_list) {
local ($suite, $test_dir, $test_file) = split("/", $test);
# *-n.js is a negative test, expect exit code 3 (runtime error)
local $expected_exit = ($test =~ /\-n\.js$/) ? 3 : 0;
local $got_exit, $exit_signal;
local $bug_line;
if ($user_exit) {
return;
}
if ($last_suite ne $suite || $last_test_dir ne $test_dir) {
$shell_command = $engine_command;
if (-f $opt_suite_path . $suite . "/shell.js") {
$shell_command .= $file_param . $opt_suite_path . $suite .
"/shell.js";
}
if (-f $opt_suite_path . $suite . "/" . $test_dir . "/shell.js") {
$shell_command .= $file_param . $opt_suite_path . $suite .
"/" . $test_dir . "/shell.js";
}
$last_suite = $suite;
$last_test_dir = $test_dir;
}
&dd ("executing: " . $shell_command . $file_param . $opt_suite_path .
$test);
open (OUTPUT, $shell_command . $file_param . $opt_suite_path . $test .
" 2>&1 |");
@output = <OUTPUT>;
close (OUTPUT);
if ($os_type ne "WIN") {
$got_exit = ($? >> 8);
$exit_signal = ($? & 255);
} else {
$got_exit = $?;
$exit_signal = 0;
}
$failure_lines = "";
$bug_line = "";
foreach $line (@output) {
if ($line =~ /expect(ed)?\s*exit\s*code\s*\:?\s*(\n+)/i) {
$expected_exit = $1;
&dd ("Test case expects exit code $expect_exit");
}
if ($line =~ /failed!/i) {
$failure_lines .= $line;
}
if ($line =~ /bugnumber\s*\:?\s*(.*)/i) {
$1 =~ /(\n+)/;
$bug_line = "<a href='$opt_bug_url$1' target='other_window'>" .
"Bug Number $1</a>";
}
}
if (!@output) {
@output = ("Testcase produced no output!");
}
if ($got_exit != $expected_exit) {
&report_failure ($test, "Expected exit code " .
"$expected_exit, got $got_exit\n" .
"Testcase terminated with signal $exit_signal\n" .
"Complete testcase output was:\n" .
join ("\n",@output), $bug_line);
} elsif ($failure_lines) {
&report_failure ($test, "Failure messages were:\n" . $failure_lines,
$bug_line);
}
&dd ("exit code $got_exit, exit signal $exit_signal.");
$tests_completed++;
}
}
sub write_results {
local $list_name = ($opt_test_list_file) ?
"List '$opt_test_list_file'" : "All tests";
local $completion_date = localtime;
local $failure_pct = int(($failures_reported / $tests_completed) * 10000) /
100;
&dd ("Writing output to $opt_output_file.");
open (OUTPUT, "> $opt_output_file") ||
die ("Could not create output file $opt_output_file");
print OUTPUT
("<html><head>\n" .
"<title>Test results, $opt_engine_type, $list_name</title>\n" .
"</head>\n" .
"<body bgcolor='white'>\n" .
"<a name='tippy_top'></a>\n" .
"<h2>Test results, $opt_engine_type, $list_name</h2><br>\n" .
"<p class='results_summary'>\n" .
($#test_list + 1) . " test(s) selected, $tests_completed test(s) " .
"completed, $failures_reported failures reported " .
"($failure_pct% failed)<br>\n" .
"Engine command line: $engine_command<br>\n" .
"OS type: $os_type<br>\n");
if ($opt_engine_type eq "rhino") {
open (JAVAOUTPUT, $opt_path_to_java . "java -fullversion 2>&1 |");
print OUTPUT <JAVAOUTPUT>;
print OUTPUT "<BR>";
close (JAVAOUTPUT);
}
print OUTPUT
("Testcase execution time: $exec_time_string.<br>\n" .
"Tests completed on $completion_date.<br><br>\n");
if ($failures_reported > 0) {
print OUTPUT
("[ <a href='#fail_detail'>Failure Details</a> | " .
"<a href='#retest_list'>Retest List</a> | " .
"<a href='menu.html'>Test Selection Page</a> ]<br>\n" .
"<hr>\n" .
"<a name='fail_detail'></a>\n" .
"<h2>Failure Details</h2><br>\n<dl>" .
$html .
"</dl>\n[ <a href='#tippy_top'>Top of Page</a> | " .
"<a href='#fail_detail'>Top of Failures</a> ]<br>\n" .
"<hr>\n<pre>\n" .
"<a name='retest_list'></a>\n" .
"<h2>Retest List</h2><br>\n" .
"# Retest List, $opt_engine_type, " .
"generated $completion_date.\n" .
"# Original test base was: $list_name.\n" .
"# $tests_completed of " . ($#test_list + 1) .
" test(s) were completed, " .
"$failures_reported failures reported.\n" .
join ("\n", @failed_tests) .
"</pre>\n" .
"[ <a href='#tippy_top'>Top of Page</a> | " .
"<a href='#retest_list'>Top of Retest List</a> ]<br>\n");
} else {
print OUTPUT
("<h1>Whoop-de-doo, nothing failed!</h1>\n");
}
print OUTPUT "</body>";
close (OUTPUT);
&status ("Wrote results to '$opt_output_file'.");
if ($opt_console_failures) {
&status ("$failures_reported test(s) failed");
}
}
sub parse_args {
local $option, $value;
&dd ("checking command line options.");
Getopt::Mixed::init ($options);
$Getopt::Mixed::order = $Getopt::Mixed::RETURN_IN_ORDER;
while (($option, $value) = nextOption()) {
if ($option eq "b") {
&dd ("opt: setting bugurl to '$value'.");
$opt_bug_url = $value;
} elsif ($option eq "c") {
&dd ("opt: setting classpath to '$value'.");
$opt_classpath = $value;
} elsif ($option eq "e") {
&dd ("opt: setting engine to $value.");
$opt_engine_type = $value;
} elsif ($option eq "f") {
if (!$value) {
die ("Output file cannot be null.\n");
}
&dd ("opt: setting output file to '$value'.");
$opt_output_file = $value;
} elsif ($option eq "h") {
&usage;
} elsif ($option eq "j") {
if (!($value =~ /[\/\\]$/)) {
$value .= "/";
}
&dd ("opt: setting java path to '$value'.");
$opt_java_url = $value;
} elsif ($option eq "k") {
&dd ("opt: displaying failures on console.");
$opt_console_failures=1;
} elsif ($option eq "l" || (($option eq "") && ($lastopt eq "l"))) {
$option = "l";
&dd ("opt: adding test list '$value'.");
push (@opt_test_list_files, $value);
} elsif ($option eq "L" || (($option eq "") && ($lastopt eq "L"))) {
$option = "L";
&dd ("opt: adding negative list '$value'.");
push (@opt_neg_list_files, $value);
} elsif ($option eq "p") {
$opt_suite_path = $value;
if (!($opt_suite_path =~ /[\/\\]$/)) {
$opt_suite_path .= "/";
}
&dd ("opt: setting suite path to '$opt_suite_path'.");
} elsif ($option eq "s") {
$opt_shell_path = $value;
if (!($opt_shell_path =~ /[\/\\]$/)) {
$opt_shell_path .= "/";
}
&dd ("opt: setting shell path to '$opt_shell_path'.");
} elsif ($option eq "t") {
&dd ("opt: tracing output. (console failures at no extra charge.)");
$opt_console_failures = 1;
$opt_trace = 1;
} elsif ($option eq "u") {
&dd ("opt: setting lxr url to '$value'.");
$opt_lxr_url = $value;
} else {
&usage;
}
$lastopt = $option;
}
Getopt::Mixed::cleanup();
if (!$opt_engine_type) {
die "You must select a shell to test in.\n";
}
if (!$opt_output_file) {
$opt_output_file = "results-" . $opt_engine_type . "-" .
&get_tempfile_id . ".html";
}
&dd ("output file is '$opt_output_file'");
}
#
# print the arguments that this script expects
#
sub usage {
print STDERR
("\nusage: $0 [<options>] \n" .
"(-b|--bugurl) Bugzilla URL.\n" .
" (default is $opt_bug_url)\n" .
"(-c|--classpath) Classpath (Rhino only.)\n" .
"(-e|--engine) <type> Specify the type of engine to test. <type> " .
"is one of \n" .
" (smopt|smdebug|lcopt|lcdebug|xpcshell|" .
"rhino).\n" .
"(-f|--file) <file> Redirect output to file named <file>.\n" .
" (default is " .
"results-<engine-type>-<date-stamp>.html)\n" .
"(-h|--help) Print this message.\n" .
"(-j|--javapath) Location of java executable.\n" .
"(-k|--confail) Log failures to console (also.)\n" .
"(-l|--list) <file> ... List of tests to execute.\n" .
"(-L|--neglist) <file> ... List of tests to skip.\n" .
"(-p|--testpath) <path> Root of the test suite. (default is ./)\n" .
"(-s|--shellpath) <path> Location of JavaScript shell.\n" .
"(-t|--trace) Trace script execution.\n" .
"(-u|--lxrurl) <url> Complete URL to tests subdirectory on lxr.\n" .
" (default is $opt_lxr_url)\n\n");
exit (1);
}
#
# get the shell command used to start the (either) engine
#
sub get_engine_command {
local $retval;
if ($opt_engine_type eq "rhino") {
&dd ("getting rhino engine command.");
$retval = &get_rhino_engine_command;
} elsif ($opt_engine_type eq "xpcshell") {
&dd ("getting xpcshell engine command.");
$retval = &get_xpc_engine_command;
} elsif ($opt_engine_type =~ /^lc(opt|debug)$/) {
&dd ("getting liveconnect engine command.");
$retval = &get_lc_engine_command;
} elsif ($opt_engine_type =~ /^sm(opt|debug)$/) {
&dd ("getting spidermonkey engine command.");
$retval = &get_sm_engine_command;
} else {
die ("Unknown engine type selected, '$opt_engine_type'.\n");
}
&dd ("got '$retval'");
return $retval;
}
#
# get the shell command used to run rhino
#
sub get_rhino_engine_command {
local $retval = $opt_java_path . "java ";
if ($opt_shell_path) {
$opt_classpath = ($opt_classpath) ?
$opt_classpath . ":" . $opt_shell_path :
$opt_shell_path;
}
if ($opt_classpath) {
$retval .= "-classpath $opt_classpath ";
}
$retval .= "org.mozilla.javascript.tools.shell.Main";
return $retval;
}
#
# get the shell command used to run xpcshell
#
sub get_xpc_engine_command {
local $m5_home = @ENV{"MOZILLA_FIVE_HOME"} ||
die ("You must set MOZILLA_FIVE_HOME to use the xpcshell" ,
($os_type eq "WIN") ? "." : ", also " .
"setting LD_LIBRARY_PATH to the same directory may get rid of " .
"any 'library not found' errors.\n");
if (($os_type ne "WIN") && (!@ENV{"LD_LIBRARY_PATH"})) {
print STDERR "-#- WARNING: LD_LIBRARY_PATH is not set, xpcshell may " .
"not be able to find the required components.\n";
}
if (!($m5_home =~ /[\/\\]$/)) {
$m5_home .= "/";
}
return $m5_home . "xpcshell";
}
#
# get the shell command used to run spidermonkey
#
sub get_sm_engine_command {
local $retval;
if ($os_type eq "WIN") {
# spidermonkey on windows
if ($opt_shell_path) {
$retval = $opt_shell_path;
if (!($retval =~ /[\/\\]$/)) {
$retval .= "/";
}
} else {
if ($opt_engine_type eq "smopt") {
$retval = "../src/Release/";
} else {
$retval = "../src/Debug/";
}
}
$retval .= "jsshell.exe";
} else {
# spidermonkey on un*x
if ($opt_shell_path) {
$retval = $opt_shell_path;
if (!($retval =~ /[\/\\]$/)) {
$retval .= "/";
}
} else {
$retval = $opt_suite_path . "../src/";
opendir (SRC_DIR_FILES, $retval);
local @src_dir_files = readdir(SRC_DIR_FILES);
closedir (SRC_DIR_FILES);
local $dir, $object_dir;
local $pattern = ($opt_engine_type eq "smdebug") ?
'DBG.OBJ' : 'OPT.OBJ';
foreach $dir (@src_dir_files) {
if ($dir =~ $pattern) {
$object_dir = $dir;
break;
}
}
if (!$object_dir) {
die ("Could not locate an object directory in $retval " .
"matching the pattern *$pattern. Have you built the " .
"engine?\n");
}
$retval .= $object_dir . "/";
}
$retval .= "js";
}
if (!(-x $retval)) {
die ("$retval is not a valid executable on this system.\n");
}
return $retval;
}
#
# get the shell command used to run the liveconnect shell
#
sub get_lc_engine_command {
local $retval;
if ($opt_shell_path) {
$retval = $opt_shell_path;
if (!($retval =~ /[\/\\]$/)) {
$retval .= "/";
}
} else {
$retval = $opt_suite_path . "../src/liveconnect/";
opendir (SRC_DIR_FILES, $retval);
local @src_dir_files = readdir(SRC_DIR_FILES);
closedir (SRC_DIR_FILES);
local $dir, $object_dir;
local $pattern = ($opt_engine_type eq "lcdebug") ?
'DBG.OBJ' : 'OPT.OBJ';
foreach $dir (@src_dir_files) {
if ($dir =~ $pattern) {
$object_dir = $dir;
break;
}
}
if (!$object_dir) {
die ("Could not locate an object directory in $retval " .
"matching the pattern *$pattern. Have you built the " .
"engine?\n");
}
$retval .= $object_dir . "/";
}
if ($os_type eq "WIN") {
$retval .= "lcshell.exe";
} else {
$retval .= "lcshell";
}
if (!(-x $retval)) {
die ("$retval is not a valid executable on this system.\n");
}
return $retval;
}
sub get_os_type {
local $uname = `uname -a`;
if ($uname =~ /WIN/) {
$uname = "WIN";
} else {
chop $uname;
}
&dd ("get_os_type returning '$uname'.");
return $uname;
}
sub get_test_list {
local @test_list;
local @neg_list;
if ($#opt_test_list_files > -1) {
local $list_file;
&dd ("getting test list from user specified source.");
foreach $list_file (@opt_test_list_files) {
push (@test_list, &expand_user_test_list($list_file));
}
} else {
&dd ("no list file, groveling in '$opt_suite_path'.");
@test_list = &get_default_test_list($opt_suite_path);
}
if ($#opt_neg_list_files > -1) {
local $list_file;
local $orig_size = $#test_list + 1;
local $actually_skipped;
&dd ("getting negative list from user specified source.");
foreach $list_file (@opt_neg_list_files) {
push (@neg_list, &expand_user_test_list($list_file));
}
@test_list = &subtract_arrays (\@test_list, \@neg_list);
$actually_skipped = $orig_size - ($#test_list + 1);
&dd ($actually_skipped . " of " . ($#test_list + 1) .
" tests will be skipped.");
&dd ((($#neg_list + 1) - $actually_skipped) . " skip tests were " .
"not actually part of the test list.");
}
return @test_list;
}
#
# reads $list_file, storing non-comment lines into an array.
# lines in the form suite_dir/[*] or suite_dir/test_dir/[*] are expanded
# to include all test files under the specified directory
#
sub expand_user_test_list {
local ($list_file) = @_;
local @retval = ();
if ($list_file =~ /\.js$/ || -d $list_file) {
push (@retval, &expand_test_list_entry($list_file));
} else {
open (TESTLIST, $list_file) ||
die("Error opening test list file '$list_file': $!\n");
while (<TESTLIST>) {
s/\n$//;
if (!(/\s*\#/)) {
# It's not a comment, so process it
push (@retval, &expand_test_list_entry($_));
}
}
close (TESTLIST);
}
return @retval;
}
sub expand_test_list_entry {
local ($entry) = @_;
local @retval;
if ($entry =~ /\.js$/) {
# it's a regular entry, add it to the list
if (-f $entry) {
push (@retval, $entry);
} else {
status ("testcase '$entry' not found.");
}
} elsif ($entry =~ /(.*\/[^\*][^\/]*)\/?\*?$/) {
# Entry is in the form suite_dir/test_dir[/*]
# so iterate all tests under it
local $suite_and_test_dir = $1;
local @test_files = &get_js_files ($opt_suite_path .
$suite_and_test_dir);
local $i;
foreach $i (0 .. $#test_files) {
$test_files[$i] = $suite_and_test_dir . "/" .
$test_files[$i];
}
splice (@retval, $#retval + 1, 0, @test_files);
} elsif ($entry =~ /([^\*][^\/]*)\/?\*?$/) {
# Entry is in the form suite_dir[/*]
# so iterate all test dirs and tests under it
local $suite = $1;
local @test_dirs = &get_subdirs ($opt_suite_path . $suite);
local $test_dir;
foreach $test_dir (@test_dirs) {
local @test_files = &get_js_files ($opt_suite_path . $suite . "/" .
$test_dir);
local $i;
foreach $i (0 .. $#test_files) {
$test_files[$i] = $suite . "/" . $test_dir . "/" .
$test_files[$i];
}
splice (@retval, $#retval + 1, 0, @test_files);
}
} else {
die ("Dont know what to do with list entry '$entry'.\n");
}
return @retval;
}
#
# Grovels through $suite_path, searching for *all* test files. Used when the
# user doesn't supply a test list.
#
sub get_default_test_list {
local ($suite_path) = @_;
local @suite_list = &get_subdirs($suite_path);
local $suite;
local @retval;
foreach $suite (@suite_list) {
local @test_dir_list = get_subdirs ($suite_path . $suite);
local $test_dir;
foreach $test_dir (@test_dir_list) {
local @test_list = get_js_files ($suite_path . $suite . "/" .
$test_dir);
local $test;
foreach $test (@test_list) {
$retval[$#retval + 1] = $suite_path . $suite . "/" . $test_dir .
"/" . $test;
}
}
}
return @retval;
}
#
# generate an output file name based on the date
#
sub get_tempfile_id {
local ($sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $isdst) =
&get_padded_time (localtime);
return $year . "-" . $mon . "-" . $mday . "-" . $hour . $min . $sec;
}
sub get_padded_time {
local ($sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $isdst) = @_;
$mon++;
$mon = &zero_pad($mon);
$year= ($year < 2000) ? "19" . $year : $year;
$mday= &zero_pad($mday);
$sec = &zero_pad($sec);
$min = &zero_pad($min);
$hour = &zero_pad($hour);
return ($sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $isdst);
}
sub zero_pad {
local ($string) = @_;
$string = ($string < 10) ? "0" . $string : $string;
return $string;
}
sub subtract_arrays {
local ($whole_ref, $part_ref) = @_;
local @whole = @$whole_ref;
local @part = @$part_ref;
local $line;
foreach $line (@part) {
@whole = grep (!/$line/, @whole);
}
return @whole;
}
#
# given a directory, return an array of all subdirectories
#
sub get_subdirs {
local ($dir) = @_;
local @subdirs;
if (!($dir =~ /\/$/)) {
$dir = $dir . "/";
}
opendir (DIR, $dir) || die ("couldn't open directory $dir: $!");
local @testdir_contents = readdir(DIR);
closedir(DIR);
foreach (@testdir_contents) {
if ((-d ($dir . $_)) && ($_ ne 'CVS') && ($_ ne '.') && ($_ ne '..')) {
@subdirs[$#subdirs + 1] = $_;
}
}
return @subdirs;
}
#
# given a directory, return an array of all the js files that are in it.
#
sub get_js_files {
local ($test_subdir) = @_;
local @js_file_array;
opendir (TEST_SUBDIR, $test_subdir) || die ("couldn't open directory " .
"$test_subdir: $!");
@subdir_files = readdir(TEST_SUBDIR);
closedir( TEST_SUBDIR );
foreach (@subdir_files) {
if ($_ =~ /\.js$/) {
$js_file_array[$#js_file_array+1] = $_;
}
}
return @js_file_array;
}
sub report_failure {
local ($test, $message, $bug_line) = @_;
$failures_reported++;
if ($opt_console_failures) {
print STDERR ("*-* Testcase $test failed:\n$message\n");
}
$message =~ s/\n/<br>\n/g;
$html .= "<a name='failure$failures_reported'></a>";
if ($opt_lxr_url) {
$test =~ /\/?([^\/]+\/[^\/]+\/[^\/]+)$/;
$test = $1;
$html .= "<dd><b>".
"Testcase <a target='other_window' href='$opt_lxr_url$test'>$1</a> " .
"failed</b> $bug_line<br>\n";
} else {
$html .= "<dd><b>".
"Testcase $test failed</b> $bug_line<br>\n";
}
$html .= " [ ";
if ($failures_reported > 1) {
$html .= "<a href='#failure" . ($failures_reported - 1) . "'>" .
"Previous Failure</a> | ";
}
$html .= "<a href='#failure" . ($failures_reported + 1) . "'>" .
"Next Failure</a> | " .
"<a href='#tippy_top'>Top of Page</a> ]<br>\n" .
"<tt>$message</tt><br>\n";
@failed_tests[$#failed_tests + 1] = $test;
}
sub dd {
if ($opt_trace) {
print ("-*- ", @_ , "\n");
}
}
sub status {
print ("-#- ", @_ , "\n");
}
sub int_handler {
local $resp;
do {
print ("\n** User Break: Just [Q]uit, Quit and [R]eport, [C]ontinue ?");
$resp = <STDIN>;
} until ($resp =~ /[QqRrCc]/);
if ($resp =~ /[Qq]/) {
print ("User Exit. No results were generated.\n");
exit;
} elsif ($resp =~ /[Rr]/) {
$user_exit = 1;
}
}

View File

@ -1,802 +1,2 @@
#!/usr/bin/perl
#
# The contents of this file are subject to the Netscape Public
# License Version 1.1 (the "License"); you may not use this file
# except in compliance with the License. You may obtain a copy of
# the License at http://www.mozilla.org/NPL/
#
# Software distributed under the License is distributed on an "AS
# IS" basis, WITHOUT WARRANTY OF ANY KIND, either express oqr
# implied. See the License for the specific language governing
# rights and limitations under the License.
#
# The Original Code is JavaScript Core Tests.
#
# The Initial Developer of the Original Code is Netscape
# Communications Corporation. Portions created by Netscape are
# Copyright (C) 1997-1999 Netscape Communications Corporation. All
# Rights Reserved.
#
# Alternatively, the contents of this file may be used under the
# terms of the GNU Public License (the "GPL"), in which case the
# provisions of the GPL are applicable instead of those above.
# If you wish to allow use of your version of this file only
# under the terms of the GPL and not to allow others to use your
# version of this file under the NPL, indicate your decision by
# deleting the provisions above and replace them with the notice
# and other provisions required by the GPL. If you do not delete
# the provisions above, a recipient may use your version of this
# file under either the NPL or the GPL.
#
# Contributers:
# Robert Ginda
#
# Second cut at runtests.pl script originally by
# Christine Begle (cbegle@netscape.com)
# Branched 11/01/99
#
use Getopt::Mixed "nextOption";
# command line option defaults
local $opt_classpath = "";
local $opt_engine_type = "";
local $opt_output_file = "";
local $opt_test_list_file = "";
local $opt_suite_path = "./";
local $opt_shell_path = "";
local $opt_java_path = "";
local $opt_bug_url = "http://bugzilla.mozilla.org/show_bug.cgi?id=";
local $opt_trace = 0;
local $opt_console_failures = 0;
local $opt_lxr_url = "http://lxr.mozilla.org/mozilla/source/js/tests/";
# command line option definition
local $options = "b=s bugurl>b c=s classpath>c e=s engine>e f=s file>f " .
"h help>h i j=s javapath>j k confail>k l=s list>l p=s testpath>p " .
"s=s shellpath>s t trace>t u=s lxrurl>u";
&parse_args;
local $os_type = &get_os_type;
local $engine_command = &get_engine_command;
local $user_exit = 0;
local $html = "";
local @failed_tests;
local $failures_reported = 0;
local $tests_completed = 0;
local @test_list = &get_test_list;
local $exec_time_string;
local $start_time = time;
if ($os_type ne "WIN") {
$SIG{INT} = 'int_handler';
}
&execute_tests (@test_list);
local $exec_time = (time - $start_time);
local $exec_mins = int($exec_time / 60);
local $exec_secs = ($exec_time % 60);
if ($exec_mins > 0) {
$exec_time_string = "$exec_mins minutes, $exec_secs seconds";
} else {
$exec_time_string = "$exec_secs seconds";
}
&write_results;
#End.
sub execute_tests {
local (@test_list) = @_;
local $test, $shell_command, $line, @output;
local $file_param = " -f ";
local $last_suite, $last_test_dir;
local $failure_lines;
&status ("Executing " . ($#test_list + 1) . " test(s).");
foreach $test (@test_list) {
local ($suite, $test_dir, $test_file) = split("/", $test);
# *-n.js is a negative test, expect exit code 3 (runtime error)
local $expected_exit = ($test =~ /\-n\.js$/) ? 3 : 0;
local $got_exit, $exit_signal;
local $bug_line;
if ($user_exit) {
return;
}
if ($last_suite ne $suite || $last_test_dir ne $test_dir) {
$shell_command = $engine_command;
if (-f $opt_suite_path . $suite . "/shell.js") {
$shell_command .= $file_param . $opt_suite_path . $suite .
"/shell.js";
}
if (-f $opt_suite_path . $suite . "/" . $test_dir . "/shell.js") {
$shell_command .= $file_param . $opt_suite_path . $suite .
"/" . $test_dir . "/shell.js";
}
$last_suite = $suite;
$last_test_dir = $test_dir;
}
&dd ("executing: " . $shell_command . $file_param . $opt_suite_path .
$test);
open (OUTPUT, $shell_command . $file_param . $opt_suite_path . $test .
" 2>&1 |");
@output = <OUTPUT>;
close (OUTPUT);
if ($os_type ne "WIN") {
$got_exit = ($? >> 8);
$exit_signal = ($? & 255);
} else {
$got_exit = $?;
$exit_signal = 0;
}
$failure_lines = "";
$bug_line = "";
foreach $line (@output) {
if ($line =~ /expect(ed)?\s*exit\s*code\s*\:?\s*(\n+)/i) {
$expected_exit = $1;
&dd ("Test case expects exit code $expect_exit");
}
if ($line =~ /failed!/i) {
$failure_lines .= $line;
}
if ($line =~ /bugnumber\s*\:?\s*(.*)/i) {
$1 =~ /(\n+)/;
$bug_line = "<a href='$opt_bug_url$1' target='other_window'>" .
"Bug Number $1</a>";
}
}
if (!@output) {
@output = ("Testcase produced no output!");
}
if ($got_exit != $expected_exit) {
&report_failure ($test, "Expected exit code " .
"$expected_exit, got $got_exit\n" .
"Testcase terminated with signal $exit_signal\n" .
"Complete testcase output was:\n" .
join ("\n",@output), $bug_line);
} elsif ($failure_lines) {
&report_failure ($test, "Failure messages were:\n" . $failure_lines,
$bug_line);
}
&dd ("exit code $got_exit, exit signal $exit_signal.");
$tests_completed++;
}
}
sub write_results {
local $list_name = ($opt_test_list_file) ?
"List '$opt_test_list_file'" : "All tests";
local ($sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $isdst) =
&get_padded_time(localtime);
local $failure_pct = int(($failures_reported / $tests_completed) * 10000) /
100;
&dd ("Writing output to $opt_output_file.");
open (OUTPUT, "> $opt_output_file") ||
die ("Could not create output file $opt_output_file");
print OUTPUT
("<html><head>\n" .
"<title>Test results, $opt_engine_type, $list_name</title>\n" .
"</head>\n" .
"<body bgcolor='white'>\n" .
"<a name='tippy_top'></a>\n" .
"<h2>Test results, $opt_engine_type, $list_name</h2><br>\n" .
"<p class='results_summary'>\n" .
($#test_list + 1) . " test(s) selected, $tests_completed test(s) " .
"completed, $failures_reported failures reported " .
"($failure_pct% failed)<br>\n" .
"Engine command line: $engine_command<br>\n" .
"OS type: $os_type<br>\n" .
"Testcase execution time: $exec_time_string.<br><br>\n");
if ($failures_reported > 0) {
print OUTPUT
("[ <a href='#fail_detail'>Failure Details</a> | " .
"<a href='#retest_list'>Retest List</a> | " .
"<a href='menu.html'>Test Selection Page</a> ]<br>\n" .
"<hr>\n" .
"<a name='fail_detail'></a>\n" .
"<h2>Failure Details</h2><br>\n<dl>" .
$html .
"</dl>\n[ <a href='#tippy_top'>Top of Page</a> | " .
"<a href='#fail_detail'>Top of Failures</a> ]<br>\n" .
"<hr>\n<pre>\n" .
"<a name='retest_list'></a>\n" .
"<h2>Retest List</h2><br>\n" .
"# Retest List, $opt_engine_type, " .
"generated $mon/$mday/$year $hour:$min.\n" .
"# Original test base was: $list_name.\n" .
"# $tests_completed of " . ($#test_list + 1) .
" test(s) were completed, " .
"$failures_reported failures reported.\n" .
join ("\n", @failed_tests) .
"</pre>\n" .
"[ <a href='#tippy_top'>Top of Page</a> | " .
"<a href='#retest_list'>Top of Retest List</a> ]<br>\n");
} else {
print OUTPUT
("<h1>Whoop-de-doo, nothing failed!</h1>\n");
}
print OUTPUT "</body>";
close (OUTPUT);
&status ("Wrote results to '$opt_output_file'.");
if ($opt_console_failures) {
&status ("$failures_reported test(s) failed");
}
}
sub parse_args {
local $option, $value;
&dd ("checking command line options.");
Getopt::Mixed::init ($options);
while (($option, $value) = nextOption()) {
if ($option eq "b") {
&dd ("opt: setting bugurl to '$value'.");
$opt_bug_url = $value;
} elsif ($option eq "c") {
&dd ("opt: setting classpath to '$value'.");
$opt_classpath = $value;
} elsif ($option eq "e") {
&dd ("opt: setting engine to $value.");
$opt_engine_type = $value;
} elsif ($option eq "f") {
if (!$value) {
die ("Output file cannot be null.\n");
}
&dd ("opt: setting output file to '$value'.");
$opt_output_file = $value;
} elsif ($option eq "h") {
&usage;
} elsif ($option eq "j") {
if (!($value =~ /[\/\\]$/)) {
$value .= "/";
}
&dd ("opt: setting java path to '$value'.");
$opt_java_url = $value;
} elsif ($option eq "k") {
&dd ("opt: displaying failures on console.");
$opt_console_failures=1;
} elsif ($option eq "l") {
&dd ("opt: setting test list to '$value'.");
$opt_test_list_file = $value;
} elsif ($option eq "p") {
$opt_suite_path = $value;
if (!($opt_suite_path =~ /[\/\\]$/)) {
$opt_suite_path .= "/";
}
&dd ("opt: setting suite path to '$opt_suite_path'.");
} elsif ($option eq "s") {
$opt_shell_path = $value;
if (!($opt_shell_path =~ /[\/\\]$/)) {
$opt_shell_path .= "/";
}
&dd ("opt: setting shell path to '$opt_shell_path'.");
} elsif ($option eq "t") {
&dd ("opt: tracing output. (console failures at no extra charge.)");
$opt_console_failures = 1;
$opt_trace = 1;
} elsif ($option eq "u") {
&dd ("opt: setting lxr url to '$value'.");
$opt_lxr_url = $value;
} else {
&usage;
}
}
Getopt::Mixed::cleanup();
if (!$opt_engine_type) {
die "You must select a shell to test in.\n";
}
if (!$opt_output_file) {
$opt_output_file = "results-" . $opt_engine_type . "-" .
&get_tempfile_id . ".html";
}
&dd ("output file is '$opt_output_file'");
}
#
# print the arguments that this script expects
#
sub usage {
print STDERR
("\nusage: $0 [<options>] \n" .
"(-b|--bugurl) Bugzilla URL.\n" .
" (default is $opt_bug_url)\n" .
"(-c|--classpath) Classpath (Rhino only.)\n" .
"(-e|--engine) <type> Specify the type of engine to test.\n" .
" <type> is one of (smopt|smdebug|lcopt|lcdebug|" .
"xpcshell|rhino).\n" .
"(-f|--file) <file> Redirect output to file named <file>.\n" .
" (default is " .
"results-<engine-type>-<date-stamp>.html)\n" .
"(-h|--help) Print this message.\n" .
"(-j|--javapath) Location of java executable.\n" .
"(-k|--confail) Log failures to console (also.)\n" .
"(-l|--list) <file> List of tests to execute.\n" .
"(-p|--testpath) <path> Root of the test suite. (default is ./)\n" .
"(-s|--shellpath) <path> Location of JavaScript shell.\n" .
"(-t|--trace) Trace script execution.\n" .
"(-u|--lxrurl) <url> Complete URL to tests subdirectory on lxr.\n" .
" (default is $opt_lxr_url)\n\n");
exit (1);
}
#
# get the shell command used to start the (either) engine
#
sub get_engine_command {
local $retval;
if ($opt_engine_type eq "rhino") {
&dd ("getting rhino engine command.");
$retval = &get_rhino_engine_command;
} elsif ($opt_engine_type eq "xpcshell") {
&dd ("getting xpcshell engine command.");
$retval = &get_xpc_engine_command;
} elsif ($opt_engine_type =~ /^lc(opt|debug)$/) {
&dd ("getting liveconnect engine command.");
$retval = &get_lc_engine_command;
} elsif ($opt_engine_type =~ /^sm(opt|debug)$/) {
&dd ("getting spidermonkey engine command.");
$retval = &get_sm_engine_command;
} else {
die ("Unknown engine type selected, '$opt_engine_type'.\n");
}
&dd ("got '$retval'");
return $retval;
}
#
# get the shell command used to run rhino
#
sub get_rhino_engine_command {
local $retval = $opt_java_path . "java ";
if ($opt_shell_path) {
$opt_classpath = ($opt_classpath) ?
$opt_classpath . ":" . $opt_shell_path :
$opt_shell_path;
}
if ($opt_classpath) {
$retval .= "-classpath $opt_classpath ";
}
$retval .= "org.mozilla.javascript.tools.shell.Main";
return $retval;
}
#
# get the shell command used to run xpcshell
#
sub get_xpc_engine_command {
local $m5_home = @ENV{"MOZILLA_FIVE_HOME"} ||
die ("You must set MOZILLA_FIVE_HOME to use the xpcshell" ,
($os_type eq "WIN") ? "." : ", also " .
"setting LD_LIBRARY_PATH to the same directory may get rid of " .
"any 'library not found' errors.\n");
if (($os_type ne "WIN") && (!@ENV{"LD_LIBRARY_PATH"})) {
print STDERR "-#- WARNING: LD_LIBRARY_PATH is not set, xpcshell may " .
"not be able to find the required components.\n";
}
if (!($m5_home =~ /[\/\\]$/)) {
$m5_home .= "/";
}
return $m5_home . "xpcshell";
}
#
# get the shell command used to run spidermonkey
#
sub get_sm_engine_command {
local $retval;
if ($os_type eq "WIN") {
# spidermonkey on windows
if ($opt_shell_path) {
$retval = $opt_shell_path;
if (!($retval =~ /[\/\\]$/)) {
$retval .= "/";
}
} else {
if ($opt_engine_type eq "smopt") {
$retval = "../src/Release/";
} else {
$retval = "../src/Debug/";
}
}
$retval .= "jsshell.exe";
} else {
# spidermonkey on un*x
if ($opt_shell_path) {
$retval = $opt_shell_path;
if (!($retval =~ /[\/\\]$/)) {
$retval .= "/";
}
} else {
$retval = $opt_suite_path . "../src/";
opendir (SRC_DIR_FILES, $retval);
local @src_dir_files = readdir(SRC_DIR_FILES);
closedir (SRC_DIR_FILES);
local $dir, $object_dir;
local $pattern = ($opt_engine_type eq "smdebug") ?
'DBG.OBJ' : 'OPT.OBJ';
foreach $dir (@src_dir_files) {
if ($dir =~ $pattern) {
$object_dir = $dir;
break;
}
}
if (!$object_dir) {
die ("Could not locate an object directory in $retval " .
"matching the pattern *$pattern. Have you built the " .
"engine?\n");
}
$retval .= $object_dir . "/";
}
$retval .= "js";
}
if (!(-x $retval)) {
die ("$retval is not a valid executable on this system.\n");
}
return $retval;
}
#
# get the shell command used to run the liveconnect shell
#
sub get_lc_engine_command {
local $retval;
if ($opt_shell_path) {
$retval = $opt_shell_path;
if (!($retval =~ /[\/\\]$/)) {
$retval .= "/";
}
} else {
$retval = $opt_suite_path . "../src/liveconnect/";
opendir (SRC_DIR_FILES, $retval);
local @src_dir_files = readdir(SRC_DIR_FILES);
closedir (SRC_DIR_FILES);
local $dir, $object_dir;
local $pattern = ($opt_engine_type eq "lcdebug") ?
'DBG.OBJ' : 'OPT.OBJ';
foreach $dir (@src_dir_files) {
if ($dir =~ $pattern) {
$object_dir = $dir;
break;
}
}
if (!$object_dir) {
die ("Could not locate an object directory in $retval " .
"matching the pattern *$pattern. Have you built the " .
"engine?\n");
}
$retval .= $object_dir . "/";
}
if ($os_type eq "WIN") {
$retval .= "lcshell.exe";
} else {
$retval .= "lcshell";
}
if (!(-x $retval)) {
die ("$retval is not a valid executable on this system.\n");
}
return $retval;
}
sub get_os_type {
local $uname = `uname -a`;
if ($uname =~ /WIN/) {
$uname = "WIN";
} else {
chop $uname;
}
&dd ("get_os_type returning '$uname'.");
return $uname;
}
sub get_test_list {
local @test_list;
if ($opt_test_list_file) {
&dd ("getting test list from file $opt_test_list_file.");
@test_list = &get_user_test_list($opt_test_list_file);
} else {
&dd ("no list file, groveling in '$opt_suite_path'.");
@test_list = &get_default_test_list($opt_suite_path);
}
return @test_list;
}
#
# reads $list_file, storing non-comment lines into an array.
#
sub get_user_test_list {
local ($list_file) = @_;
local @retval;
if (!(-f $list_file)) {
print STDERR "Test List file '$list_file' not found.\n";
exit 1;
}
if ($list_file =~ /\.js$/) {
return ($list_file);
}
open (TESTLIST, $list_file) ||
die("Error opening test list file '$list_file': $!\n");
while (<TESTLIST>) {
s/\n$//;
if (!(/\s*\#/)) {
$retval[$#retval + 1] = $_;
}
}
close (TESTLIST);
return @retval;
}
#
# Grovels through $suite_path, searching for *all* test files. Used when the
# user doesn't supply a test list.
#
sub get_default_test_list {
local ($suite_path) = @_;
local @suite_list = &get_subdirs($suite_path);
local $suite;
local @retval;
&status ("Scanning for tests in $suite_path.");
foreach $suite (@suite_list) {
local @test_dir_list = get_subdirs ($suite_path . $suite);
local $test_dir;
foreach $test_dir (@test_dir_list) {
local @test_list = get_js_files ($suite_path . $suite . "/" .
$test_dir);
local $test;
foreach $test (@test_list) {
$retval[$#retval + 1] = $suite_path . $suite . "/" . $test_dir .
"/" . $test;
}
}
}
return @retval;
}
#
# generate an output file name based on the date
#
sub get_tempfile_id {
local ($sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $isdst) =
&get_padded_time (localtime);
return $year . "-" . $mon . "-" . $mday . "-" . $hour . $min . $sec;
}
sub get_padded_time {
local ($sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $isdst) = @_;
$mon++;
$mon = &zero_pad($mon);
$year= ($year < 2000) ? "19" . $year : $year;
$mday= &zero_pad($mday);
$sec = &zero_pad($sec);
$min = &zero_pad($min);
$hour = &zero_pad($hour);
return ($sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $isdst);
}
sub zero_pad {
local ($string) = @_;
$string = ($string < 10) ? "0" . $string : $string;
return $string;
}
#
# given a directory, return an array of all subdirectories
#
sub get_subdirs {
local ($dir) = @_;
local @subdirs;
if (!($dir =~ /\/$/)) {
$dir = $dir . "/";
}
opendir (DIR, $dir) || die ("couldn't open directory $dir: $!");
local @testdir_contents = readdir(DIR);
closedir(DIR);
foreach (@testdir_contents) {
if ((-d ($dir . $_)) && ($_ ne 'CVS') && ($_ ne '.') && ($_ ne '..')) {
@subdirs[$#subdirs + 1] = $_;
}
}
return @subdirs;
}
#
# given a directory, return an array of all the js files that are in it.
#
sub get_js_files {
local ($test_subdir) = @_;
local @js_file_array;
opendir (TEST_SUBDIR, $test_subdir) || die ("couldn't open directory " .
"$test_subdir: $!");
@subdir_files = readdir(TEST_SUBDIR);
closedir( TEST_SUBDIR );
foreach (@subdir_files) {
if ($_ =~ /\.js$/) {
$js_file_array[$#js_file_array+1] = $_;
}
}
return @js_file_array;
}
sub report_failure {
local ($test, $message, $bug_line) = @_;
$failures_reported++;
if ($opt_console_failures) {
print STDERR ("*-* Testcase $test failed:\n$message\n");
}
$message =~ s/\n/<br>\n/g;
$html .= "<a name='failure$failures_reported'></a>";
if ($opt_lxr_url) {
$test =~ /\/?([^\/]+\/[^\/]+\/[^\/]+)$/;
$test = $1;
$html .= "<dd><b>".
"Testcase <a target='other_window' href='$opt_lxr_url$test'>$1</a> " .
"failed</b> $bug_line<br>\n";
} else {
$html .= "<dd><b>".
"Testcase $test failed</b> $bug_line<br>\n";
}
$html .= " [ ";
if ($failures_reported > 1) {
$html .= "<a href='#failure" . ($failures_reported - 1) . "'>" .
"Previous Failure</a> | ";
}
$html .= "<a href='#failure" . ($failures_reported + 1) . "'>" .
"Next Failure</a> | " .
"<a href='#tippy_top'>Top of Page</a> ]<br>\n" .
"<tt>$message</tt><br>\n";
@failed_tests[$#failed_tests + 1] = $test;
}
sub dd {
if ($opt_trace) {
print ("-*- ", @_ , "\n");
}
}
sub status {
print ("-#- ", @_ , "\n");
}
sub int_handler {
local $resp;
do {
print ("\n** User Break: Just [Q]uit, Quit and [R]eport, [C]ontinue ?");
$resp = <STDIN>;
} until ($resp =~ /[QqRrCc]/);
if ($resp =~ /[Qq]/) {
print ("User Exit. No results were generated.\n");
exit;
} elsif ($resp =~ /[Rr]/) {
$user_exit = 1;
}
}
print ("This is no longer the test driver, please use jsDriver.pl instead.");