]> git.saurik.com Git - apple/javascriptcore.git/blob - tests/mozilla/jsDriver.pl
JavaScriptCore-554.1.tar.gz
[apple/javascriptcore.git] / tests / mozilla / jsDriver.pl
1 #!/usr/bin/perl
2 #
3 # The contents of this file are subject to the Netscape Public
4 # License Version 1.1 (the "License"); you may not use this file
5 # except in compliance with the License. You may obtain a copy of
6 # the License at http://www.mozilla.org/NPL/
7 #
8 # Software distributed under the License is distributed on an "AS
9 # IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
10 # implied. See the License for the specific language governing
11 # rights and limitations under the License.
12 #
13 # The Original Code is JavaScript Core Tests.
14 #
15 # The Initial Developer of the Original Code is Netscape
16 # Communications Corporation. Portions created by Netscape are
17 # Copyright (C) 1997-1999 Netscape Communications Corporation. All
18 # Rights Reserved.
19 #
20 # Alternatively, the contents of this file may be used under the
21 # terms of the GNU Public License (the "GPL"), in which case the
22 # provisions of the GPL are applicable instead of those above.
23 # If you wish to allow use of your version of this file only
24 # under the terms of the GPL and not to allow others to use your
25 # version of this file under the NPL, indicate your decision by
26 # deleting the provisions above and replace them with the notice
27 # and other provisions required by the GPL. If you do not delete
28 # the provisions above, a recipient may use your version of this
29 # file under either the NPL or the GPL.
30 #
31 # Contributers:
32 # Robert Ginda <rginda@netscape.com>
33 #
34 # Second cut at runtests.pl script originally by
35 # Christine Begle (cbegle@netscape.com)
36 # Branched 11/01/99
37 #
38
39 use strict;
40 use Getopt::Mixed "nextOption";
41
42 my $os_type = &get_os_type;
43 my $unixish = (($os_type ne "WIN") && ($os_type ne "MAC"));
44 my $path_sep = ($os_type eq "MAC") ? ":" : "/";
45 my $win_sep = ($os_type eq "WIN")? &get_win_sep : "";
46 my $redirect_command = ($os_type ne "MAC") ? " 2>&1" : "";
47
48 # command line option defaults
49 my $opt_suite_path;
50 my $opt_trace = 0;
51 my $opt_classpath = "";
52 my $opt_rhino_opt = 0;
53 my $opt_rhino_ms = 0;
54 my @opt_engine_list;
55 my $opt_engine_type = "";
56 my $opt_engine_params = "";
57 my $opt_user_output_file = 0;
58 my $opt_output_file = "";
59 my @opt_test_list_files;
60 my @opt_neg_list_files;
61 my $opt_shell_path = "";
62 my $opt_java_path = "";
63 my $opt_bug_url = "http://bugzilla.mozilla.org/show_bug.cgi?id=";
64 my $opt_console_failures = 0;
65 my $opt_lxr_url = "./"; # "http://lxr.mozilla.org/mozilla/source/js/tests/";
66 my $opt_exit_munge = ($os_type ne "MAC") ? 1 : 0;
67 my $opt_arch= "";
68
69 # command line option definition
70 my $options = "a=s arch>a b=s bugurl>b c=s classpath>c e=s engine>e f=s file>f " .
71 "h help>h i j=s javapath>j k confail>k l=s list>l L=s neglist>L " .
72 "o=s opt>o p=s testpath>p s=s shellpath>s t trace>t u=s lxrurl>u " .
73 "x noexitmunge>x";
74
75 if ($os_type eq "MAC") {
76 $opt_suite_path = `directory`;
77 $opt_suite_path =~ s/[\n\r]//g;
78 $opt_suite_path .= ":";
79 } else {
80 $opt_suite_path = "./";
81 }
82
83 &parse_args;
84
85 my $user_exit = 0;
86 my ($engine_command, $html, $failures_reported, $tests_completed,
87 $exec_time_string);
88 my @failed_tests;
89 my @test_list = &get_test_list;
90
91 if ($#test_list == -1) {
92 die ("Nothing to test.\n");
93 }
94
95 if ($unixish) {
96 # on unix, ^C pauses the tests, and gives the user a chance to quit but
97 # report on what has been done, to just quit, or to continue (the
98 # interrupted test will still be skipped.)
99 # windows doesn't handle the int handler they way we want it to,
100 # so don't even pretend to let the user continue.
101 $SIG{INT} = 'int_handler';
102 }
103
104 &main;
105
106 #End.
107
108 sub main {
109 my $start_time;
110
111 while ($opt_engine_type = pop (@opt_engine_list)) {
112 dd ("Testing engine '$opt_engine_type'");
113
114 $engine_command = &get_engine_command;
115 $html = "";
116 @failed_tests = ();
117 $failures_reported = 0;
118 $tests_completed = 0;
119 $start_time = time;
120
121
122 &execute_tests (@test_list);
123
124 my $exec_time = (time - $start_time);
125 my $exec_hours = int($exec_time / 60 / 60);
126 $exec_time -= $exec_hours * 60 * 60;
127 my $exec_mins = int($exec_time / 60);
128 $exec_time -= $exec_mins * 60;
129 my $exec_secs = ($exec_time % 60);
130
131 if ($exec_hours > 0) {
132 $exec_time_string = "$exec_hours hours, $exec_mins minutes, " .
133 "$exec_secs seconds";
134 } elsif ($exec_mins > 0) {
135 $exec_time_string = "$exec_mins minutes, $exec_secs seconds";
136 } else {
137 $exec_time_string = "$exec_secs seconds";
138 }
139
140 if (!$opt_user_output_file) {
141 $opt_output_file = &get_tempfile_name;
142 }
143
144 &write_results;
145
146 }
147 }
148
149 sub execute_tests {
150 my (@test_list) = @_;
151 my ($test, $shell_command, $line, @output, $path);
152 my $file_param = " -f ";
153 my ($last_suite, $last_test_dir);
154
155 # Don't run any shell.js files as tests; they are only utility files
156 @test_list = grep (!/shell\.js$/, @test_list);
157
158 &status ("Executing " . ($#test_list + 1) . " test(s).");
159 foreach $test (@test_list) {
160 my ($suite, $test_dir, $test_file) = split($path_sep, $test);
161 # *-n.js is a negative test, expect exit code 3 (runtime error)
162 my $expected_exit = ($test =~ /\-n\.js$/) ? 3 : 0;
163 my ($got_exit, $exit_signal);
164 my $failure_lines;
165 my $bug_number;
166 my $status_lines;
167
168 # user selected [Q]uit from ^C handler.
169 if ($user_exit) {
170 return;
171 }
172
173 # Append the shell.js files to the shell_command if they're there.
174 # (only check for their existance if the suite or test_dir has changed
175 # since the last time we looked.)
176 if ($last_suite ne $suite || $last_test_dir ne $test_dir) {
177 $shell_command = $opt_arch . " ";
178
179 $shell_command .= &xp_path($engine_command) . " -s ";
180
181 $path = &xp_path($opt_suite_path . $suite . "/shell.js");
182 if (-f $path) {
183 $shell_command .= $file_param . $path;
184 }
185
186 $path = &xp_path($opt_suite_path . $suite . "/" .
187 $test_dir . "/shell.js");
188 if (-f $path) {
189 $shell_command .= $file_param . $path;
190 }
191
192 $last_suite = $suite;
193 $last_test_dir = $test_dir;
194 }
195
196 $path = &xp_path($opt_suite_path . $test);
197
198 print ($shell_command . $file_param . $path . "\n");
199 &dd ("executing: " . $shell_command . $file_param . $path);
200
201 open (OUTPUT, $shell_command . $file_param . $path .
202 $redirect_command . " |");
203 @output = <OUTPUT>;
204 close (OUTPUT);
205
206 @output = grep (!/js\>/, @output);
207
208 if ($opt_exit_munge == 1) {
209 # signal information in the lower 8 bits, exit code above that
210 $got_exit = ($? >> 8);
211 $exit_signal = ($? & 255);
212 } else {
213 # user says not to munge the exit code
214 $got_exit = $?;
215 $exit_signal = 0;
216 }
217
218 $failure_lines = "";
219 $bug_number = "";
220 $status_lines = "";
221
222 foreach $line (@output) {
223
224 # watch for testcase to proclaim what exit code it expects to
225 # produce (0 by default)
226 if ($line =~ /expect(ed)?\s*exit\s*code\s*\:?\s*(\d+)/i) {
227 $expected_exit = $2;
228 &dd ("Test case expects exit code $expected_exit");
229 }
230
231 # watch for failures
232 if ($line =~ /failed!/i) {
233 $failure_lines .= $line;
234 }
235
236 # and watch for bugnumbers
237 # XXX This only allows 1 bugnumber per testfile, should be
238 # XXX modified to allow for multiple.
239 if ($line =~ /bugnumber\s*\:?\s*(.*)/i) {
240 $1 =~ /(\n+)/;
241 $bug_number = $1;
242 }
243
244 # and watch for status
245 if ($line =~ /status/i) {
246 $status_lines .= $line;
247 }
248
249 }
250
251 if (!@output) {
252 @output = ("Testcase produced no output!");
253 }
254
255 if ($got_exit != $expected_exit) {
256 # full testcase output dumped on mismatched exit codes,
257 &report_failure ($test, "Expected exit code " .
258 "$expected_exit, got $got_exit\n" .
259 "Testcase terminated with signal $exit_signal\n" .
260 "Complete testcase output was:\n" .
261 join ("\n",@output), $bug_number);
262 } elsif ($failure_lines) {
263 # only offending lines if exit codes matched
264 &report_failure ($test, "$status_lines\n".
265 "Failure messages were:\n$failure_lines",
266 $bug_number);
267 }
268
269 &dd ("exit code $got_exit, exit signal $exit_signal.");
270
271 $tests_completed++;
272 }
273 }
274
275 sub write_results {
276 my ($list_name, $neglist_name);
277 my $completion_date = localtime;
278 my $failure_pct = int(($failures_reported / $tests_completed) * 10000) /
279 100;
280 &dd ("Writing output to $opt_output_file.");
281
282 if ($#opt_test_list_files == -1) {
283 $list_name = "All tests";
284 } elsif ($#opt_test_list_files < 10) {
285 $list_name = join (", ", @opt_test_list_files);
286 } else {
287 $list_name = "($#opt_test_list_files test files specified)";
288 }
289
290 if ($#opt_neg_list_files == -1) {
291 $neglist_name = "(none)";
292 } elsif ($#opt_test_list_files < 10) {
293 $neglist_name = join (", ", @opt_neg_list_files);
294 } else {
295 $neglist_name = "($#opt_neg_list_files skip files specified)";
296 }
297
298 open (OUTPUT, "> $opt_output_file") ||
299 die ("Could not create output file $opt_output_file");
300
301 print OUTPUT
302 ("<html><head>\n" .
303 "<title>Test results, $opt_engine_type</title>\n" .
304 "</head>\n" .
305 "<body bgcolor='white'>\n" .
306 "<a name='tippy_top'></a>\n" .
307 "<h2>Test results, $opt_engine_type</h2><br>\n" .
308 "<p class='results_summary'>\n" .
309 "Test List: $list_name<br>\n" .
310 "Skip List: $neglist_name<br>\n" .
311 ($#test_list + 1) . " test(s) selected, $tests_completed test(s) " .
312 "completed, $failures_reported failures reported " .
313 "($failure_pct% failed)<br>\n" .
314 "Engine command line: $engine_command<br>\n" .
315 "OS type: $os_type<br>\n");
316
317 if ($opt_engine_type =~ /^rhino/) {
318 open (JAVAOUTPUT, $opt_java_path . "java -fullversion " .
319 $redirect_command . " |");
320 print OUTPUT <JAVAOUTPUT>;
321 print OUTPUT "<BR>";
322 close (JAVAOUTPUT);
323 }
324
325 print OUTPUT
326 ("Testcase execution time: $exec_time_string.<br>\n" .
327 "Tests completed on $completion_date.<br><br>\n");
328
329 if ($failures_reported > 0) {
330 print OUTPUT
331 ("[ <a href='#fail_detail'>Failure Details</a> | " .
332 "<a href='#retest_list'>Retest List</a> | " .
333 "<a href='menu.html'>Test Selection Page</a> ]<br>\n" .
334 "<hr>\n" .
335 "<a name='fail_detail'></a>\n" .
336 "<h2>Failure Details</h2><br>\n<dl>" .
337 $html .
338 "</dl>\n[ <a href='#tippy_top'>Top of Page</a> | " .
339 "<a href='#fail_detail'>Top of Failures</a> ]<br>\n" .
340 "<hr>\n<pre>\n" .
341 "<a name='retest_list'></a>\n" .
342 "<h2>Retest List</h2><br>\n" .
343 "# Retest List, $opt_engine_type, " .
344 "generated $completion_date.\n" .
345 "# Original test base was: $list_name.\n" .
346 "# $tests_completed of " . ($#test_list + 1) .
347 " test(s) were completed, " .
348 "$failures_reported failures reported.\n" .
349 join ("\n", @failed_tests) );
350 #"</pre>\n" .
351 # "[ <a href='#tippy_top'>Top of Page</a> | " .
352 # "<a href='#retest_list'>Top of Retest List</a> ]<br>\n");
353 } else {
354 print OUTPUT
355 ("<h1>Whoop-de-doo, nothing failed!</h1>\n");
356 }
357
358 #print OUTPUT "</body>";
359
360 close (OUTPUT);
361
362 &status ("Wrote results to '$opt_output_file'.");
363
364 if ($opt_console_failures) {
365 &status ("$failures_reported test(s) failed");
366 }
367
368 }
369
370 sub parse_args {
371 my ($option, $value, $lastopt);
372
373 &dd ("checking command line options.");
374
375 Getopt::Mixed::init ($options);
376 $Getopt::Mixed::order = $Getopt::Mixed::RETURN_IN_ORDER;
377
378 while (($option, $value) = nextOption()) {
379
380 if ($option eq "a") {
381 &dd ("opt: running with architecture $value.");
382 $value =~ s/^ //;
383 $opt_arch = "arch -$value";
384
385 } elsif ($option eq "b") {
386 &dd ("opt: setting bugurl to '$value'.");
387 $opt_bug_url = $value;
388
389 } elsif ($option eq "c") {
390 &dd ("opt: setting classpath to '$value'.");
391 $opt_classpath = $value;
392
393 } elsif (($option eq "e") || (($option eq "") && ($lastopt eq "e"))) {
394 &dd ("opt: adding engine $value.");
395 push (@opt_engine_list, $value);
396
397 } elsif ($option eq "f") {
398 if (!$value) {
399 die ("Output file cannot be null.\n");
400 }
401 &dd ("opt: setting output file to '$value'.");
402 $opt_user_output_file = 1;
403 $opt_output_file = $value;
404
405 } elsif ($option eq "h") {
406 &usage;
407
408 } elsif ($option eq "j") {
409 if (!($value =~ /[\/\\]$/)) {
410 $value .= "/";
411 }
412 &dd ("opt: setting java path to '$value'.");
413 $opt_java_path = $value;
414
415 } elsif ($option eq "k") {
416 &dd ("opt: displaying failures on console.");
417 $opt_console_failures=1;
418
419 } elsif ($option eq "l" || (($option eq "") && ($lastopt eq "l"))) {
420 $option = "l";
421 &dd ("opt: adding test list '$value'.");
422 push (@opt_test_list_files, $value);
423
424 } elsif ($option eq "L" || (($option eq "") && ($lastopt eq "L"))) {
425 $option = "L";
426 &dd ("opt: adding negative list '$value'.");
427 push (@opt_neg_list_files, $value);
428
429 } elsif ($option eq "o") {
430 $opt_engine_params = $value;
431 &dd ("opt: setting engine params to '$opt_engine_params'.");
432
433 } elsif ($option eq "p") {
434 $opt_suite_path = $value;
435
436 if ($os_type eq "MAC") {
437 if (!($opt_suite_path =~ /\:$/)) {
438 $opt_suite_path .= ":";
439 }
440 } else {
441 if (!($opt_suite_path =~ /[\/\\]$/)) {
442 $opt_suite_path .= "/";
443 }
444 }
445
446 &dd ("opt: setting suite path to '$opt_suite_path'.");
447
448 } elsif ($option eq "s") {
449 $opt_shell_path = $value;
450 &dd ("opt: setting shell path to '$opt_shell_path'.");
451
452 } elsif ($option eq "t") {
453 &dd ("opt: tracing output. (console failures at no extra charge.)");
454 $opt_console_failures = 1;
455 $opt_trace = 1;
456
457 } elsif ($option eq "u") {
458 &dd ("opt: setting lxr url to '$value'.");
459 $opt_lxr_url = $value;
460
461 } elsif ($option eq "x") {
462 &dd ("opt: turning off exit munging.");
463 $opt_exit_munge = 0;
464
465 } else {
466 &usage;
467 }
468
469 $lastopt = $option;
470
471 }
472
473 Getopt::Mixed::cleanup();
474
475 if ($#opt_engine_list == -1) {
476 die "You must select a shell to test in.\n";
477 }
478
479 }
480
481 #
482 # print the arguments that this script expects
483 #
484 sub usage {
485 print STDERR
486 ("\nusage: $0 [<options>] \n" .
487 "(-a|--arch) <arch> run with a specific architecture on mac\n" .
488 "(-b|--bugurl) Bugzilla URL.\n" .
489 " (default is $opt_bug_url)\n" .
490 "(-c|--classpath) Classpath (Rhino only.)\n" .
491 "(-e|--engine) <type> ... Specify the type of engine(s) to test.\n" .
492 " <type> is one or more of\n" .
493 " (squirrelfish|smopt|smdebug|lcopt|lcdebug|xpcshell|" .
494 "rhino|rhinoi|rhinoms|rhinomsi|rhino9|rhinoms9).\n" .
495 "(-f|--file) <file> Redirect output to file named <file>.\n" .
496 " (default is " .
497 "results-<engine-type>-<date-stamp>.html)\n" .
498 "(-h|--help) Print this message.\n" .
499 "(-j|--javapath) Location of java executable.\n" .
500 "(-k|--confail) Log failures to console (also.)\n" .
501 "(-l|--list) <file> ... List of tests to execute.\n" .
502 "(-L|--neglist) <file> ... List of tests to skip.\n" .
503 "(-o|--opt) <options> Options to pass to the JavaScript engine.\n" .
504 " (Make sure to quote them!)\n" .
505 "(-p|--testpath) <path> Root of the test suite. (default is ./)\n" .
506 "(-s|--shellpath) <path> Location of JavaScript shell.\n" .
507 "(-t|--trace) Trace script execution.\n" .
508 "(-u|--lxrurl) <url> Complete URL to tests subdirectory on lxr.\n" .
509 " (default is $opt_lxr_url)\n" .
510 "(-x|--noexitmunge) Don't do exit code munging (try this if it\n" .
511 " seems like your exit codes are turning up\n" .
512 " as exit signals.)\n");
513 exit (1);
514
515 }
516
517 #
518 # get the shell command used to start the (either) engine
519 #
520 sub get_engine_command {
521
522 my $retval;
523
524 if ($opt_engine_type eq "rhino") {
525 &dd ("getting rhino engine command.");
526 $opt_rhino_opt = 0;
527 $opt_rhino_ms = 0;
528 $retval = &get_rhino_engine_command;
529 } elsif ($opt_engine_type eq "rhinoi") {
530 &dd ("getting rhinoi engine command.");
531 $opt_rhino_opt = -1;
532 $opt_rhino_ms = 0;
533 $retval = &get_rhino_engine_command;
534 } elsif ($opt_engine_type eq "rhino9") {
535 &dd ("getting rhino engine command.");
536 $opt_rhino_opt = 9;
537 $opt_rhino_ms = 0;
538 $retval = &get_rhino_engine_command;
539 } elsif ($opt_engine_type eq "rhinoms") {
540 &dd ("getting rhinoms engine command.");
541 $opt_rhino_opt = 0;
542 $opt_rhino_ms = 1;
543 $retval = &get_rhino_engine_command;
544 } elsif ($opt_engine_type eq "rhinomsi") {
545 &dd ("getting rhinomsi engine command.");
546 $opt_rhino_opt = -1;
547 $opt_rhino_ms = 1;
548 $retval = &get_rhino_engine_command;
549 } elsif ($opt_engine_type eq "rhinoms9") {
550 &dd ("getting rhinomsi engine command.");
551 $opt_rhino_opt = 9;
552 $opt_rhino_ms = 1;
553 $retval = &get_rhino_engine_command;
554 } elsif ($opt_engine_type eq "xpcshell") {
555 &dd ("getting xpcshell engine command.");
556 $retval = &get_xpc_engine_command;
557 } elsif ($opt_engine_type =~ /^lc(opt|debug)$/) {
558 &dd ("getting liveconnect engine command.");
559 $retval = &get_lc_engine_command;
560 } elsif ($opt_engine_type =~ /^sm(opt|debug)$/) {
561 &dd ("getting spidermonkey engine command.");
562 $retval = &get_sm_engine_command;
563 } elsif ($opt_engine_type =~ /^ep(opt|debug)$/) {
564 &dd ("getting epimetheus engine command.");
565 $retval = &get_ep_engine_command;
566 } elsif ($opt_engine_type eq "squirrelfish") {
567 &dd ("getting squirrelfish engine command.");
568 $retval = &get_squirrelfish_engine_command;
569 } else {
570 die ("Unknown engine type selected, '$opt_engine_type'.\n");
571 }
572
573 $retval .= " $opt_engine_params";
574
575 &dd ("got '$retval'");
576
577 return $retval;
578
579 }
580
581 #
582 # get the shell command used to run rhino
583 #
584 sub get_rhino_engine_command {
585 my $retval = $opt_java_path . ($opt_rhino_ms ? "jview " : "java ");
586
587 if ($opt_shell_path) {
588 $opt_classpath = ($opt_classpath) ?
589 $opt_classpath . ":" . $opt_shell_path :
590 $opt_shell_path;
591 }
592
593 if ($opt_classpath) {
594 $retval .= ($opt_rhino_ms ? "/cp:p" : "-classpath") . " $opt_classpath ";
595 }
596
597 $retval .= "org.mozilla.javascript.tools.shell.Main";
598
599 if ($opt_rhino_opt) {
600 $retval .= " -opt $opt_rhino_opt";
601 }
602
603 return $retval;
604
605 }
606
607 #
608 # get the shell command used to run xpcshell
609 #
610 sub get_xpc_engine_command {
611 my $retval;
612 my $m5_home = @ENV{"MOZILLA_FIVE_HOME"} ||
613 die ("You must set MOZILLA_FIVE_HOME to use the xpcshell" ,
614 (!$unixish) ? "." : ", also " .
615 "setting LD_LIBRARY_PATH to the same directory may get rid of " .
616 "any 'library not found' errors.\n");
617
618 if (($unixish) && (!@ENV{"LD_LIBRARY_PATH"})) {
619 print STDERR "-#- WARNING: LD_LIBRARY_PATH is not set, xpcshell may " .
620 "not be able to find the required components.\n";
621 }
622
623 if (!($m5_home =~ /[\/\\]$/)) {
624 $m5_home .= "/";
625 }
626
627 $retval = $m5_home . "xpcshell";
628
629 if ($os_type eq "WIN") {
630 $retval .= ".exe";
631 }
632
633 $retval = &xp_path($retval);
634
635 if (($os_type ne "MAC") && !(-x $retval)) {
636 # mac doesn't seem to deal with -x correctly
637 die ($retval . " is not a valid executable on this system.\n");
638 }
639
640 return $retval;
641
642 }
643
644 #
645 # get the shell command used to run squirrelfish
646 #
647 sub get_squirrelfish_engine_command {
648 my $retval;
649
650 if ($opt_shell_path) {
651 # FIXME: Quoting the path this way won't work with paths with quotes in
652 # them. A better fix would be to use the multi-parameter version of
653 # open(), but that doesn't work on ActiveState Perl.
654 $retval = "\"" . $opt_shell_path . "\"";
655 } else {
656 die "Please specify a full path to the squirrelfish testing engine";
657 }
658
659 return $retval;
660 }
661
662 #
663 # get the shell command used to run spidermonkey
664 #
665 sub get_sm_engine_command {
666 my $retval;
667
668 # Look for Makefile.ref style make first.
669 # (On Windows, spidermonkey can be made by two makefiles, each putting the
670 # executable in a diferent directory, under a different name.)
671
672 if ($opt_shell_path) {
673 # if the user provided a path to the shell, return that.
674 $retval = $opt_shell_path;
675
676 } else {
677
678 if ($os_type eq "MAC") {
679 $retval = $opt_suite_path . ":src:macbuild:JS";
680 } else {
681 $retval = $opt_suite_path . "../src/";
682 opendir (SRC_DIR_FILES, $retval);
683 my @src_dir_files = readdir(SRC_DIR_FILES);
684 closedir (SRC_DIR_FILES);
685
686 my ($dir, $object_dir);
687 my $pattern = ($opt_engine_type eq "smdebug") ?
688 'DBG.OBJ' : 'OPT.OBJ';
689
690 # scan for the first directory matching
691 # the pattern expected to hold this type (debug or opt) of engine
692 foreach $dir (@src_dir_files) {
693 if ($dir =~ $pattern) {
694 $object_dir = $dir;
695 last;
696 }
697 }
698
699 if (!$object_dir && $os_type ne "WIN") {
700 die ("Could not locate an object directory in $retval " .
701 "matching the pattern *$pattern. Have you built the " .
702 "engine?\n");
703 }
704
705 if (!(-x $retval . $object_dir . "/js.exe") && ($os_type eq "WIN")) {
706 # On windows, you can build with js.mak as well as Makefile.ref
707 # (Can you say WTF boys and girls? I knew you could.)
708 # So, if the exe the would have been built by Makefile.ref isn't
709 # here, check for the js.mak version before dying.
710 if ($opt_shell_path) {
711 $retval = $opt_shell_path;
712 if (!($retval =~ /[\/\\]$/)) {
713 $retval .= "/";
714 }
715 } else {
716 if ($opt_engine_type eq "smopt") {
717 $retval = "../src/Release/";
718 } else {
719 $retval = "../src/Debug/";
720 }
721 }
722
723 $retval .= "jsshell.exe";
724
725 } else {
726 $retval .= $object_dir . "/js";
727 if ($os_type eq "WIN") {
728 $retval .= ".exe";
729 }
730 }
731 } # mac/ not mac
732
733 $retval = &xp_path($retval);
734
735 } # (user provided a path)
736
737
738 if (($os_type ne "MAC") && !(-x $retval)) {
739 # mac doesn't seem to deal with -x correctly
740 die ($retval . " is not a valid executable on this system.\n");
741 }
742
743 return $retval;
744
745 }
746
747 #
748 # get the shell command used to run epimetheus
749 #
750 sub get_ep_engine_command {
751 my $retval;
752
753 if ($opt_shell_path) {
754 # if the user provided a path to the shell, return that -
755 $retval = $opt_shell_path;
756
757 } else {
758 my $dir;
759 my $os;
760 my $debug;
761 my $opt;
762 my $exe;
763
764 $dir = $opt_suite_path . "../../js2/src/";
765
766 if ($os_type eq "MAC") {
767 #
768 # On the Mac, the debug and opt builds lie in the same directory -
769 #
770 $os = "macbuild:";
771 $debug = "";
772 $opt = "";
773 $exe = "JS2";
774 } elsif ($os_type eq "WIN") {
775 $os = "winbuild/Epimetheus/";
776 $debug = "Debug/";
777 $opt = "Release/";
778 $exe = "Epimetheus.exe";
779 } else {
780 $os = "";
781 $debug = "";
782 $opt = ""; # <<<----- XXX THIS IS NOT RIGHT! CHANGE IT!
783 $exe = "epimetheus";
784 }
785
786
787 if ($opt_engine_type eq "epdebug") {
788 $retval = $dir . $os . $debug . $exe;
789 } else {
790 $retval = $dir . $os . $opt . $exe;
791 }
792
793 $retval = &xp_path($retval);
794
795 }# (user provided a path)
796
797
798 if (($os_type ne "MAC") && !(-x $retval)) {
799 # mac doesn't seem to deal with -x correctly
800 die ($retval . " is not a valid executable on this system.\n");
801 }
802
803 return $retval;
804 }
805
806 #
807 # get the shell command used to run the liveconnect shell
808 #
809 sub get_lc_engine_command {
810 my $retval;
811
812 if ($opt_shell_path) {
813 $retval = $opt_shell_path;
814 } else {
815 if ($os_type eq "MAC") {
816 die "Don't know how to run the lc shell on the mac yet.\n";
817 } else {
818 $retval = $opt_suite_path . "../src/liveconnect/";
819 opendir (SRC_DIR_FILES, $retval);
820 my @src_dir_files = readdir(SRC_DIR_FILES);
821 closedir (SRC_DIR_FILES);
822
823 my ($dir, $object_dir);
824 my $pattern = ($opt_engine_type eq "lcdebug") ?
825 'DBG.OBJ' : 'OPT.OBJ';
826
827 foreach $dir (@src_dir_files) {
828 if ($dir =~ $pattern) {
829 $object_dir = $dir;
830 last;
831 }
832 }
833
834 if (!$object_dir) {
835 die ("Could not locate an object directory in $retval " .
836 "matching the pattern *$pattern. Have you built the " .
837 "engine?\n");
838 }
839
840 $retval .= $object_dir . "/";
841
842 if ($os_type eq "WIN") {
843 $retval .= "lcshell.exe";
844 } else {
845 $retval .= "lcshell";
846 }
847 } # mac/ not mac
848
849 $retval = &xp_path($retval);
850
851 } # (user provided a path)
852
853
854 if (($os_type ne "MAC") && !(-x $retval)) {
855 # mac doesn't seem to deal with -x correctly
856 die ("$retval is not a valid executable on this system.\n");
857 }
858
859 return $retval;
860
861 }
862
863 sub get_os_type {
864
865 if ("\n" eq "\015") {
866 return "MAC";
867 }
868
869 my $uname = `uname -a`;
870
871 if ($uname =~ /WIN/) {
872 $uname = "WIN";
873 } else {
874 chop $uname;
875 }
876
877 &dd ("get_os_type returning '$uname'.");
878 return $uname;
879
880 }
881
882 sub get_test_list {
883 my @test_list;
884 my @neg_list;
885
886 if ($#opt_test_list_files > -1) {
887 my $list_file;
888
889 &dd ("getting test list from user specified source.");
890
891 foreach $list_file (@opt_test_list_files) {
892 push (@test_list, &expand_user_test_list($list_file));
893 }
894 } else {
895 &dd ("no list file, groveling in '$opt_suite_path'.");
896
897 @test_list = &get_default_test_list($opt_suite_path);
898 }
899
900 if ($#opt_neg_list_files > -1) {
901 my $list_file;
902 my $orig_size = $#test_list + 1;
903 my $actually_skipped;
904
905 &dd ("getting negative list from user specified source.");
906
907 foreach $list_file (@opt_neg_list_files) {
908 push (@neg_list, &expand_user_test_list($list_file));
909 }
910
911 @test_list = &subtract_arrays (\@test_list, \@neg_list);
912
913 $actually_skipped = $orig_size - ($#test_list + 1);
914
915 &dd ($actually_skipped . " of " . $orig_size .
916 " tests will be skipped.");
917 &dd ((($#neg_list + 1) - $actually_skipped) . " skip tests were " .
918 "not actually part of the test list.");
919
920
921 }
922
923 return @test_list;
924
925 }
926
927 #
928 # reads $list_file, storing non-comment lines into an array.
929 # lines in the form suite_dir/[*] or suite_dir/test_dir/[*] are expanded
930 # to include all test files under the specified directory
931 #
932 sub expand_user_test_list {
933 my ($list_file) = @_;
934 my @retval = ();
935
936 #
937 # Trim off the leading path separator that begins relative paths on the Mac.
938 # Each path will get concatenated with $opt_suite_path, which ends in one.
939 #
940 # Also note:
941 #
942 # We will call expand_test_list_entry(), which does pattern-matching on $list_file.
943 # This will make the pattern-matching the same as it would be on Linux/Windows -
944 #
945 if ($os_type eq "MAC") {
946 $list_file =~ s/^$path_sep//;
947 }
948
949 if ($list_file =~ /\.js$/ || -d $opt_suite_path . $list_file) {
950
951 push (@retval, &expand_test_list_entry($list_file));
952
953 } else {
954
955 open (TESTLIST, $list_file) ||
956 die("Error opening test list file '$list_file': $!\n");
957
958 while (<TESTLIST>) {
959 s/\r*\n*$//;
960 if (!(/\s*\#/)) {
961 # It's not a comment, so process it
962 push (@retval, &expand_test_list_entry($_));
963 }
964 }
965
966 close (TESTLIST);
967
968 }
969
970 return @retval;
971
972 }
973
974
975 #
976 # Currently expect all paths to be RELATIVE to the top-level tests directory.
977 # One day, this should be improved to allow absolute paths as well -
978 #
979 sub expand_test_list_entry {
980 my ($entry) = @_;
981 my @retval;
982
983 if ($entry =~ /\.js$/) {
984 # it's a regular entry, add it to the list
985 if (-f $opt_suite_path . $entry) {
986 push (@retval, $entry);
987 } else {
988 status ("testcase '$entry' not found.");
989 }
990 } elsif ($entry =~ /(.*$path_sep[^\*][^$path_sep]*)$path_sep?\*?$/) {
991 # Entry is in the form suite_dir/test_dir[/*]
992 # so iterate all tests under it
993 my $suite_and_test_dir = $1;
994 my @test_files = &get_js_files ($opt_suite_path .
995 $suite_and_test_dir);
996 my $i;
997
998 foreach $i (0 .. $#test_files) {
999 $test_files[$i] = $suite_and_test_dir . $path_sep .
1000 $test_files[$i];
1001 }
1002
1003 splice (@retval, $#retval + 1, 0, @test_files);
1004
1005 } elsif ($entry =~ /([^\*][^$path_sep]*)$path_sep?\*?$/) {
1006 # Entry is in the form suite_dir[/*]
1007 # so iterate all test dirs and tests under it
1008 my $suite = $1;
1009 my @test_dirs = &get_subdirs ($opt_suite_path . $suite);
1010 my $test_dir;
1011
1012 foreach $test_dir (@test_dirs) {
1013 my @test_files = &get_js_files ($opt_suite_path . $suite .
1014 $path_sep . $test_dir);
1015 my $i;
1016
1017 foreach $i (0 .. $#test_files) {
1018 $test_files[$i] = $suite . $path_sep . $test_dir . $path_sep .
1019 $test_files[$i];
1020 }
1021
1022 splice (@retval, $#retval + 1, 0, @test_files);
1023 }
1024
1025 } else {
1026 die ("Dont know what to do with list entry '$entry'.\n");
1027 }
1028
1029 return @retval;
1030
1031 }
1032
1033 #
1034 # Grovels through $suite_path, searching for *all* test files. Used when the
1035 # user doesn't supply a test list.
1036 #
1037 sub get_default_test_list {
1038 my ($suite_path) = @_;
1039 my @suite_list = &get_subdirs($suite_path);
1040 my $suite;
1041 my @retval;
1042
1043 foreach $suite (@suite_list) {
1044 my @test_dir_list = get_subdirs ($suite_path . $suite);
1045 my $test_dir;
1046
1047 foreach $test_dir (@test_dir_list) {
1048 my @test_list = get_js_files ($suite_path . $suite . $path_sep .
1049 $test_dir);
1050 my $test;
1051
1052 foreach $test (@test_list) {
1053 $retval[$#retval + 1] = $suite . $path_sep . $test_dir .
1054 $path_sep . $test;
1055 }
1056 }
1057 }
1058
1059 return @retval;
1060
1061 }
1062
1063 #
1064 # generate an output file name based on the date
1065 #
1066 sub get_tempfile_name {
1067 my ($sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $isdst) =
1068 &get_padded_time (localtime);
1069 my $rv;
1070
1071 if ($os_type ne "MAC") {
1072 $rv = "results-" . $year . "-" . $mon . "-" . $mday . "-" . $hour .
1073 $min . $sec . "-" . $opt_engine_type;
1074 } else {
1075 $rv = "res-" . $year . $mon . $mday . $hour . $min . $sec . "-" .
1076 $opt_engine_type
1077 }
1078
1079 return $rv . ".html";
1080 }
1081
1082 sub get_padded_time {
1083 my ($sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $isdst) = @_;
1084
1085 $mon++;
1086 $mon = &zero_pad($mon);
1087 $year += 1900;
1088 $mday= &zero_pad($mday);
1089 $sec = &zero_pad($sec);
1090 $min = &zero_pad($min);
1091 $hour = &zero_pad($hour);
1092
1093 return ($sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $isdst);
1094
1095 }
1096
1097 sub zero_pad {
1098 my ($string) = @_;
1099
1100 $string = ($string < 10) ? "0" . $string : $string;
1101 return $string;
1102 }
1103
1104 sub subtract_arrays {
1105 my ($whole_ref, $part_ref) = @_;
1106 my @whole = @$whole_ref;
1107 my @part = @$part_ref;
1108 my $line;
1109
1110 foreach $line (@part) {
1111 @whole = grep (!/$line/, @whole);
1112 }
1113
1114 return @whole;
1115
1116 }
1117
1118 #
1119 # Convert unix path to mac style.
1120 #
1121 sub unix_to_mac {
1122 my ($path) = @_;
1123 my @path_elements = split ("/", $path);
1124 my $rv = "";
1125 my $i;
1126
1127 foreach $i (0 .. $#path_elements) {
1128 if ($path_elements[$i] eq ".") {
1129 if (!($rv =~ /\:$/)) {
1130 $rv .= ":";
1131 }
1132 } elsif ($path_elements[$i] eq "..") {
1133 if (!($rv =~ /\:$/)) {
1134 $rv .= "::";
1135 } else {
1136 $rv .= ":";
1137 }
1138 } elsif ($path_elements[$i] ne "") {
1139 $rv .= $path_elements[$i] . ":";
1140 }
1141
1142 }
1143
1144 $rv =~ s/\:$//;
1145
1146 return $rv;
1147 }
1148
1149 #
1150 # Convert unix path to win style.
1151 #
1152 sub unix_to_win {
1153 my ($path) = @_;
1154
1155 if ($path_sep ne $win_sep) {
1156 $path =~ s/$path_sep/$win_sep/g;
1157 }
1158
1159 return $path;
1160 }
1161
1162 #
1163 # Windows shells require "/" or "\" as path separator.
1164 # Find out the one used in the current Windows shell.
1165 #
1166 sub get_win_sep {
1167 my $path = $ENV{"PATH"} || $ENV{"Path"} || $ENV{"path"};
1168 $path =~ /\\|\//;
1169 return $&;
1170 }
1171
1172 #
1173 # Convert unix path to correct style based on platform.
1174 #
1175 sub xp_path {
1176 my ($path) = @_;
1177
1178 if ($os_type eq "MAC") {
1179 return &unix_to_mac($path);
1180 } elsif($os_type eq "WIN") {
1181 return &unix_to_win($path);
1182 } else {
1183 return $path;
1184 }
1185 }
1186
1187 sub numericcmp($$)
1188 {
1189 my ($aa, $bb) = @_;
1190
1191 my @a = split /(\d+)/, $aa;
1192 my @b = split /(\d+)/, $bb;
1193
1194 while (@a && @b) {
1195 my $a = shift @a;
1196 my $b = shift @b;
1197 return $a <=> $b if $a =~ /^\d/ && $b =~ /^\d/ && $a != $b;
1198 return $a cmp $b if $a ne $b;
1199 }
1200
1201 return @a <=> @b;
1202 }
1203
1204 #
1205 # given a directory, return an array of all subdirectories
1206 #
1207 sub get_subdirs {
1208 my ($dir) = @_;
1209 my @subdirs;
1210
1211 if ($os_type ne "MAC") {
1212 if (!($dir =~ /\/$/)) {
1213 $dir = $dir . "/";
1214 }
1215 } else {
1216 if (!($dir =~ /\:$/)) {
1217 $dir = $dir . ":";
1218 }
1219 }
1220 opendir (DIR, $dir) || die ("couldn't open directory $dir: $!");
1221 my @testdir_contents = sort numericcmp readdir(DIR);
1222 closedir(DIR);
1223
1224 foreach (@testdir_contents) {
1225 if ((-d ($dir . $_)) && ($_ ne 'CVS') && ($_ ne '.') && ($_ ne '..')) {
1226 @subdirs[$#subdirs + 1] = $_;
1227 }
1228 }
1229
1230 return @subdirs;
1231 }
1232
1233 #
1234 # given a directory, return an array of all the js files that are in it.
1235 #
1236 sub get_js_files {
1237 my ($test_subdir) = @_;
1238 my (@js_file_array, @subdir_files);
1239
1240 opendir (TEST_SUBDIR, $test_subdir) || die ("couldn't open directory " .
1241 "$test_subdir: $!");
1242 @subdir_files = sort numericcmp readdir(TEST_SUBDIR);
1243 closedir( TEST_SUBDIR );
1244
1245 foreach (@subdir_files) {
1246 if ($_ =~ /\.js$/) {
1247 $js_file_array[$#js_file_array+1] = $_;
1248 }
1249 }
1250
1251 return @js_file_array;
1252 }
1253
1254 sub report_failure {
1255 my ($test, $message, $bug_number) = @_;
1256 my $bug_line = "";
1257
1258 $failures_reported++;
1259
1260 $message =~ s/\n+/\n/g;
1261 $test =~ s/\:/\//g;
1262
1263 if ($opt_console_failures) {
1264 if($bug_number) {
1265 print STDERR ("*-* Testcase $test failed:\nBug Number $bug_number".
1266 "\n$message\n");
1267 } else {
1268 print STDERR ("*-* Testcase $test failed:\n$message\n");
1269 }
1270 }
1271
1272 $message =~ s/\n/<br>\n/g;
1273 $html .= "<a name='failure$failures_reported'></a>";
1274
1275 if ($bug_number) {
1276 $bug_line = "<a href='$opt_bug_url$bug_number' target='other_window'>".
1277 "Bug Number $bug_number</a>";
1278 }
1279
1280 if ($opt_lxr_url) {
1281 $test =~ /\/?([^\/]+\/[^\/]+\/[^\/]+)$/;
1282 $test = $1;
1283 $html .= "<dd><b>".
1284 "Testcase <a target='other_window' href='$opt_lxr_url$test'>$1</a> " .
1285 "failed</b> $bug_line<br>\n";
1286 } else {
1287 $html .= "<dd><b>".
1288 "Testcase $test failed</b> $bug_line<br>\n";
1289 }
1290
1291 $html .= " [ ";
1292 if ($failures_reported > 1) {
1293 $html .= "<a href='#failure" . ($failures_reported - 1) . "'>" .
1294 "Previous Failure</a> | ";
1295 }
1296
1297 $html .= "<a href='#failure" . ($failures_reported + 1) . "'>" .
1298 "Next Failure</a> | " .
1299 "<a href='#tippy_top'>Top of Page</a> ]<br>\n" .
1300 "<tt>$message</tt><br>\n";
1301
1302 @failed_tests[$#failed_tests + 1] = $test;
1303
1304 }
1305
1306 sub dd {
1307
1308 if ($opt_trace) {
1309 print ("-*- ", @_ , "\n");
1310 }
1311
1312 }
1313
1314 sub status {
1315
1316 print ("-#- ", @_ , "\n");
1317
1318 }
1319
1320 sub int_handler {
1321 my $resp;
1322
1323 do {
1324 print ("\n*** User Break: Just [Q]uit, Quit and [R]eport, [C]ontinue ?");
1325 $resp = <STDIN>;
1326 } until ($resp =~ /[QqRrCc]/);
1327
1328 if ($resp =~ /[Qq]/) {
1329 print ("User Exit. No results were generated.\n");
1330 exit 1;
1331 } elsif ($resp =~ /[Rr]/) {
1332 $user_exit = 1;
1333 }
1334
1335 }