Add ability to only run specific tests in run-javascriptcore-tests.
[WebKit-https.git] / Tools / Scripts / run-javascriptcore-tests
1 #!/usr/bin/perl -w
2
3 # Copyright (C) 2005-2017 Apple Inc.  All rights reserved.
4 # Copyright (C) 2007 Eric Seidel <eric@webkit.org>
5 #
6 # Redistribution and use in source and binary forms, with or without
7 # modification, are permitted provided that the following conditions
8 # are met:
9 #
10 # 1.  Redistributions of source code must retain the above copyright
11 #     notice, this list of conditions and the following disclaimer.
12 # 2.  Redistributions in binary form must reproduce the above copyright
13 #     notice, this list of conditions and the following disclaimer in the
14 #     documentation and/or other materials provided with the distribution.
15 # 3.  Neither the name of Apple Inc. ("Apple") nor the names of
16 #     its contributors may be used to endorse or promote products derived
17 #     from this software without specific prior written permission.
18 #
19 # THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
20 # EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
21 # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22 # DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
23 # DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24 # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25 # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
26 # ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
28 # THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29
30 # Script to run the WebKit Open Source Project JavaScriptCore tests (adapted from Mozilla),
31 # as well as other tests: testapi on Mac and LayoutTests/js.
32
33 use strict;
34 use File::Spec;
35 use FindBin;
36 use Getopt::Long qw(:config pass_through);
37 use JSON::PP;
38 use lib $FindBin::Bin;
39 use List::Util qw(min max);
40 use POSIX;
41 use webkitdirs;
42
43 # determine configuration
44 setConfiguration();
45 my $configuration = configuration();
46
47 # These variables are intentionally left undefined.
48 my $root;
49 my $showHelp;
50 my @extraTests = ();
51 my $jsDriverArgs;
52 my $childProcesses;
53 my $shellRunner;
54 my $makeRunner;
55 my $memoryLimited;
56
57 my $buildJSC = 1;
58
59 use constant {
60     ENV_VAR_SAYS_DO_RUN => 4,
61     ENV_VAR_SAYS_DONT_RUN => 3,
62     RUN_IF_NO_TESTS_SPECIFIED => 2,
63     DO_RUN => 1,
64     DONT_RUN => 0,
65 };
66
67 my $runTestMasm = RUN_IF_NO_TESTS_SPECIFIED;
68 my $runTestAir = RUN_IF_NO_TESTS_SPECIFIED;
69 my $runTestB3 = RUN_IF_NO_TESTS_SPECIFIED;
70 my $runTestAPI = RUN_IF_NO_TESTS_SPECIFIED;
71 my $runJSCStress = RUN_IF_NO_TESTS_SPECIFIED;
72 my $runMozillaTests = RUN_IF_NO_TESTS_SPECIFIED;
73
74 # $runJITStressTests is special because it is not for enabling a different set of tests.
75 # Instead it is only meaningful for when we want to disable using JIT test configurations
76 # on the JSC stress test or mozilla tests.
77 my $runJITStressTests = 1;
78
79 my $runQuickMode = 0;
80
81 my $forceCollectContinuously = 0;
82 my $envVars = "";
83 my $gmallocPath = undef;
84 my $gmallocDefaultPath = "/usr/lib/libgmalloc.dylib";
85
86 my $createTarball = 0;
87 my $remoteHost = 0;
88 my $failFast = 1;
89 my %jsonData = ();
90 my $remoteConfigFile;
91 my $jsonFileName;
92
93 if ($ENV{RUN_JAVASCRIPTCORE_TESTS_TESTMASM}) {
94     if ($ENV{RUN_JAVASCRIPTCORE_TESTS_TESTMASM} eq "true") {
95         $runTestMasm = ENV_VAR_SAYS_DO_RUN;
96     } elsif ($ENV{RUN_JAVASCRIPTCORE_TESTS_TESTMASM} eq "false") {
97         $runTestMasm = ENV_VAR_SAYS_DONT_RUN;
98     } else {
99         print "Don't recognize value for RUN_JAVASCRIPTCORE_TESTS_TESTMASM environment variable: '"
100             . $ENV{RUN_JAVASCRIPTCORE_TESTS_TESTMASM} . "'. Should be set to 'true' or 'false'.\n";
101     }
102 }
103
104 if ($ENV{RUN_JAVASCRIPTCORE_TESTS_TESTAIR}) {
105     if ($ENV{RUN_JAVASCRIPTCORE_TESTS_TESTAIR} eq "true") {
106         $runTestAir = ENV_VAR_SAYS_DO_RUN;
107     } elsif ($ENV{RUN_JAVASCRIPTCORE_TESTS_TESTAIR} eq "false") {
108         $runTestAir = ENV_VAR_SAYS_DONT_RUN;
109     } else {
110         print "Don't recognize value for RUN_JAVASCRIPTCORE_TESTS_TESTAIR environment variable: '"
111             . $ENV{RUN_JAVASCRIPTCORE_TESTS_TESTAIR} . "'. Should be set to 'true' or 'false'.\n";
112     }
113 }
114
115 if ($ENV{RUN_JAVASCRIPTCORE_TESTS_TESTB3}) {
116     if ($ENV{RUN_JAVASCRIPTCORE_TESTS_TESTB3} eq "true") {
117         $runTestB3 = ENV_VAR_SAYS_DO_RUN;
118     } elsif ($ENV{RUN_JAVASCRIPTCORE_TESTS_TESTB3} eq "false") {
119         $runTestB3 = ENV_VAR_SAYS_DONT_RUN;
120     } else {
121         print "Don't recognize value for RUN_JAVASCRIPTCORE_TESTS_TESTB3 environment variable: '"
122             . $ENV{RUN_JAVASCRIPTCORE_TESTS_TESTB3} . "'. Should be set to 'true' or 'false'.\n";
123     }
124 }
125
126 if ($ENV{RUN_JAVASCRIPTCORE_TESTS_TESTAPI}) {
127     if ($ENV{RUN_JAVASCRIPTCORE_TESTS_TESTAPI} eq "true") {
128         $runTestAPI = ENV_VAR_SAYS_DO_RUN;
129     } elsif ($ENV{RUN_JAVASCRIPTCORE_TESTS_TESTAPI} eq "false") {
130         $runTestAPI = ENV_VAR_SAYS_DONT_RUN;
131     } else {
132         print "Don't recognize value for RUN_JAVASCRIPTCORE_TESTS_TESTAPI environment variable: '"
133             . $ENV{RUN_JAVASCRIPTCORE_TESTS_TESTAPI} . "'. Should be set to 'true' or 'false'.\n";
134     }
135 }
136
137 if ($ENV{RUN_JAVASCRIPTCORE_TESTS_BUILD}) {
138     if ($ENV{RUN_JAVASCRIPTCORE_TESTS_BUILD} eq "true") {
139         $buildJSC = 1;
140     } elsif ($ENV{RUN_JAVASCRIPTCORE_TESTS_BUILD} eq "false") {
141         $buildJSC = 0;
142     } else {
143         print "Don't recognize value for RUN_JAVASCRIPTCORE_TESTS_BUILD environment variable: '"
144             . $ENV{RUN_JAVASCRIPTCORE_TESTS_BUILD} . "'. Should be set to 'true' or 'false'.\n";
145     }
146 }
147
148 if ($ENV{RUN_JAVASCRIPTCORE_TESTS_EXTRA_TESTS}) {
149     push @extraTests, $ENV{RUN_JAVASCRIPTCORE_TESTS_EXTRA_TESTS};
150 }
151
152 sub defaultStringForTestState {
153     my ($state) = @_;
154     if ($state == ENV_VAR_SAYS_DONT_RUN) {
155         return "will not run due to environment variable";
156     } elsif ($state == DONT_RUN) {
157         return "will not run";
158     } else {
159         return "will run";
160     }
161 }
162
163 my $programName = basename($0);
164 my $buildJSCDefault = $buildJSC ? "will check" : "will not check";
165 my $testmasmDefault = defaultStringForTestState($runTestMasm);
166 my $testairDefault = defaultStringForTestState($runTestAir);
167 my $testb3Default = defaultStringForTestState($runTestB3);
168 my $testapiDefault = defaultStringForTestState($runTestAPI);
169 my $jscStressDefault = defaultStringForTestState($runJSCStress);
170 my $mozillaTestsDefault = defaultStringForTestState($runMozillaTests);
171 my $jitStressTestsDefault = $runJITStressTests ? "will run" : " will not run";
172 my $quickModeDefault = $runQuickMode ? "some" : "all";
173 my $failFastDefault = $failFast ? "fail fast" : "don't fail fast";
174 my $filter;
175 my $usage = <<EOF;
176 Usage: $programName [options] [options to pass to build system]
177   --help                        Show this help message
178   --root=                       Path to pre-built root containing jsc
179   --[no-]ftl-jit                Turn the FTL JIT on or off
180   --[no-]build                  Check (or don't check) to see if the jsc build is up-to-date (default: $buildJSCDefault)
181   --[no-]testmasm               Only run (or don't run) testmasm (default: $testmasmDefault)
182   --[no-]testair                Only run (or don't run) testair (default: $testairDefault)
183   --[no-]testb3                 Only run (or don't run) testb3 (default: $testb3Default)
184   --[no-]testapi                Only run (or don't run) testapi (default: $testapiDefault)
185   --[no-]jsc-stress             Only run (or don't run) the JSC stress tests (default: $jscStressDefault)
186   --[no-]mozilla-tests          Only run (or don't run) the Mozilla tests (default: $mozillaTestsDefault)
187   --[no-]jit-stress-tests       Run (or don't run) the JIT stress tests (default: $jitStressTestsDefault)
188   --[no-]quick                  Run some (or all) of the regular testing modes (default: $quickModeDefault)
189                                 If the runner only runs some it will run the default and no-cjit-validate modes.
190                                 Note, this will not change the behavior of tests that specify their own modes.
191
192   --[no-]fail-fast              Stop this script when a test family reports an error or failure (default: $failFastDefault)
193   --[no-]force-collectContinuously Enable the collectContinuously mode even if it was disabled on this platform.
194   --json-output=                Create a file at specified path, listing failed stress tests in JSON format.
195   --tarball                     Create a tarball of the bundle produced by running the JSC stress tests.
196   --remote=                     Run the JSC stress tests on the specified remote host. Implies --tarball.
197   --remote-config-file=         Same as remote, but read config from JSON file.
198   --extra-tests=                Path to a file containing extra tests
199   --child-processes=            Specify the number of child processes.
200   --shell-runner                Uses the shell-based test runner instead of the default make-based runner.
201                                 In general the shell runner is slower than the make runner.
202   --make-runner                 Uses the faster make-based runner.
203
204   --memory-limited              Indicate that we are targeting the test for a memory limited device.
205                                 Skip tests tagged with //\@skip if \$memoryLimited
206
207   --filter                      Only run tests whose name matches the given regular expression.
208   --env-vars                    Pass a list of environment variables to set before running tests.
209                                 Each environment variable should be separated by a space.
210                                 e.g. \"foo=bar x=y\" (no quotes).
211   --gmalloc:                    Run tests with Guard Malloc enabled (if no path is given: $gmallocDefaultPath is used)
212
213 Environment Variables:
214   - set RUN_JAVASCRIPTCORE_TESTS_TESTMASM to "true" or "false" (no quotes) to determine if we run testmasm by default.
215   - set RUN_JAVASCRIPTCORE_TESTS_TESTAIR to "true" or "false" (no quotes) to determine if we run testair by default.
216   - set RUN_JAVASCRIPTCORE_TESTS_TESTB3 to "true" or "false" (no quotes) to determine if we run testb3 by default.
217   - set RUN_JAVASCRIPTCORE_TESTS_TESTAPI to "true" or "false" (no quotes) to determine if we run testapi by default.
218   - set RUN_JAVASCRIPTCORE_TESTS_BUILD to "true" or "false" (no quotes) to set the should-we-build-before-running-tests setting.
219   - set RUN_JAVASCRIPTCORE_TESTS_EXTRA_TESTS to the path of a yaml file or a directory of JS files to be run as part of run-javascriptcore-tests.
220
221 If one or more --<testname> options are specified, only those tests will run. For example,
222 the following only runs testmasm and testapi:
223     \$ run-javascriptcore-tests --testmasm --testapi
224
225 Otherwise, all tests will run unless the test is disabled using --no-<testname> or an
226 environment variable.
227 EOF
228
229 GetOptions(
230     'root=s' => \$root,
231     'extra-tests=s' => \@extraTests,
232     'build!' => \$buildJSC,
233     'testmasm!' => \$runTestMasm,
234     'testair!' => \$runTestAir,
235     'testb3!' => \$runTestB3,
236     'testapi!' => \$runTestAPI,
237     'jsc-stress!' => \$runJSCStress,
238     'mozilla-tests!' => \$runMozillaTests,
239     'jit-stress-tests!' => \$runJITStressTests,
240     'quick!' => \$runQuickMode,
241     'fail-fast!' => \$failFast,
242     'force-collectContinuously!' => \$forceCollectContinuously,
243     'json-output=s' => \$jsonFileName,
244     'tarball!' => \$createTarball,
245     'remote=s' => \$remoteHost,
246     'remote-config-file=s' => \$remoteConfigFile,
247     'child-processes=s' => \$childProcesses,
248     'shell-runner' => \$shellRunner,
249     'make-runner' => \$makeRunner,
250     'memory-limited' => \$memoryLimited,
251     'filter=s' => \$filter,
252     'help' => \$showHelp,
253     'env-vars=s' => \$envVars,
254     'gmalloc:s' => \$gmallocPath,
255 );
256
257
258 my $specificTestsSpecified = 0;
259 if ($runTestMasm == DO_RUN
260    || $runTestAir == DO_RUN
261    || $runTestB3 == DO_RUN
262    || $runTestAPI == DO_RUN
263    || $runJSCStress == DO_RUN
264    || $runMozillaTests == DO_RUN) {
265     $specificTestsSpecified = 1;
266 }
267
268 sub enableTestOrNot {
269     my ($state) = @_;
270     if ($state == RUN_IF_NO_TESTS_SPECIFIED || $state == ENV_VAR_SAYS_DO_RUN) {
271         return $specificTestsSpecified ? DONT_RUN : DO_RUN;
272     } elsif ($state == ENV_VAR_SAYS_DONT_RUN) {
273         return DONT_RUN;
274     }
275     return $state;
276 }
277
278 $runTestMasm = enableTestOrNot($runTestMasm);
279 $runTestAir = enableTestOrNot($runTestAir);
280 $runTestB3 = enableTestOrNot($runTestB3);
281 $runTestAPI = enableTestOrNot($runTestAPI);
282 $runJSCStress = enableTestOrNot($runJSCStress);
283 $runMozillaTests = enableTestOrNot($runMozillaTests);
284
285 # Assume any arguments left over from GetOptions are assumed to be build arguments
286 my @buildArgs = @ARGV;
287
288 if ($showHelp) {
289    print STDERR $usage;
290    exit 1;
291 }
292
293 setConfigurationProductDir(Cwd::abs_path($root)) if (defined($root));
294
295 if (defined($jsonFileName)) {
296     $jsonFileName = File::Spec->rel2abs($jsonFileName);
297 }
298
299 if (!defined($root) && $buildJSC) {
300     chdirWebKit();
301
302     push(@buildArgs, argumentsForConfiguration());
303
304     print "Running: build-jsc " . join(" ", @buildArgs) . "\n";
305     my $buildResult = system "perl", File::Spec->catfile("Tools", "Scripts", "build-jsc"), @buildArgs;
306     if ($buildResult) {
307         print STDERR "Compiling jsc failed!\n";
308         exit exitStatus($buildResult);
309     }
310 }
311
312 if (defined($gmallocPath)) {
313     if ($gmallocPath eq "") {
314         $envVars .= " DYLD_INSERT_LIBRARIES=" . $gmallocDefaultPath;
315     } else {
316         $envVars .= " DYLD_INSERT_LIBRARIES=" . $gmallocPath;
317     }
318 }
319
320 my $productDir = jscProductDir();
321 $ENV{DYLD_FRAMEWORK_PATH} = $productDir;
322 $ENV{JSCTEST_timeout} = 120 unless $ENV{JSCTEST_timeout}; # Set a 120 second timeout on all jsc tests (if environment variable not defined already).
323 $ENV{TZ}="US/Pacific"; # Some tests fail if the time zone is not set to US/Pacific (<https://webkit.org/b/136363>)
324 setPathForRunningWebKitApp(\%ENV) if isCygwin();
325
326 sub testPath {
327     my ($productDir, $testName) = @_;
328     $testName .= "_debug" if configuration() eq "Debug_All";
329     return File::Spec->catfile($productDir, $testName);
330 }
331
332 sub runTest {
333     my ($testName, $jsonTestStatusName) = @_;
334
335     chdirWebKit();
336     chdir($productDir) or die "Failed to switch directory to '$productDir'\n";
337     my @command = (testPath($productDir, $testName));
338     unshift @command, ("xcrun", "-sdk", xcodeSDK(), "sim") if willUseIOSSimulatorSDK();
339     unshift @command, wrapperPrefixIfNeeded() if shouldUseJhbuild();
340
341     if ($envVars ne "") {
342         foreach my $var (split(/\s+/, $envVars)) {
343             if ($var =~ /([^=]*)=(.*)/) {
344                 $ENV{$1} = $2;
345             }
346         }
347     }
348
349     # Use an "indirect object" so that system() won't get confused if the path
350     # contains spaces (see perldoc -f exec).
351     my $testResult = system { $command[0] } @command;
352     my $exitStatus = exitStatus($testResult);
353     print "$testName completed with rc=$testResult ($exitStatus)\n\n";
354
355     if (defined($jsonFileName)) {
356         my $testStatus = ($exitStatus == 0)? JSON::PP::true: JSON::PP::false;
357         $jsonData{$jsonTestStatusName} = $testStatus;
358     }
359
360     if ($testResult && $failFast) {
361         writeJsonDataIfApplicable();
362         exit exitStatus($testResult);
363     }
364 }
365
366 if ($runTestMasm) { runTest("testmasm", "allMasmTestsPassed") }
367 if ($runTestAir) { runTest("testair", "allAirTestsPassed") }
368 if ($runTestB3) { runTest("testb3", "allB3TestsPassed") }
369 if ($runTestAPI) { runTest("testapi", "allApiTestsPassed") }
370
371
372 # Find JavaScriptCore directory
373 chdirWebKit();
374
375 runJSCStressTests();
376
377 sub runJSCStressTests
378 {
379     my $jscStressResultsDir = $productDir . "/jsc-stress-results";
380
381     my $hasTestsToRun = 0;
382     my @testList;
383     if ($runJSCStress) {
384         @testList = (
385             "PerformanceTests/SunSpider/tests/sunspider-1.0",
386             "PerformanceTests/JetStream/cdjs/cdjs-tests.yaml",
387             "PerformanceTests/ARES-6/Air/airjs-tests.yaml",
388             "PerformanceTests/ARES-6/Basic/basic-tests.yaml",
389             "JSTests/executableAllocationFuzz.yaml",
390             "JSTests/exceptionFuzz.yaml",
391             "PerformanceTests/SunSpider/no-architecture-specific-optimizations.yaml",
392             "PerformanceTests/SunSpider/shadow-chicken.yaml",
393             "PerformanceTests/SunSpider/tests/v8-v6",
394             "JSTests/stress",
395             "JSTests/microbenchmarks",
396             "JSTests/slowMicrobenchmarks.yaml",
397             "PerformanceTests/SunSpider/profiler-test.yaml",
398             "LayoutTests/jsc-layout-tests.yaml",
399             "JSTests/typeProfiler.yaml",
400             "JSTests/controlFlowProfiler.yaml",
401             "JSTests/es6.yaml",
402             "JSTests/modules.yaml",
403             "JSTests/ChakraCore.yaml",
404             "JSTests/wasm.yaml");
405         $hasTestsToRun = 1;
406     }
407
408     if ($runMozillaTests) {
409         push(@testList, "JSTests/mozilla/mozilla-tests.yaml");
410         $hasTestsToRun = 1;
411     }
412
413     # Set LANG environment variable so the stress tests will work with newer ruby (<rdar://problem/15010705>)
414     $ENV{LANG}="en_US.UTF-8";
415     my @jscStressDriverCmd = (
416         "/usr/bin/env", "ruby", "Tools/Scripts/run-jsc-stress-tests",
417         "-j", jscPath($productDir), "-o", $jscStressResultsDir);
418
419     push(@jscStressDriverCmd, @testList);
420
421     if (isWindows() && !isCygwin()) {
422         shift @jscStressDriverCmd; # Remove /usr/bin/env
423     }
424
425     if (configuration() eq "Debug") {
426         push(@jscStressDriverCmd, "--debug");
427     }
428     
429     if ($forceCollectContinuously) {
430         push(@jscStressDriverCmd, "--force-collectContinuously");
431     }
432
433     if ($envVars ne "") {
434             push(@jscStressDriverCmd, "--env-vars");
435             push(@jscStressDriverCmd, $envVars);
436     }
437
438     if ($runQuickMode) {
439         push(@jscStressDriverCmd, "--quick");
440     }
441
442     if (!$runJITStressTests) {
443         push(@jscStressDriverCmd, "--no-jit");
444     }
445     if ($createTarball) {
446         push(@jscStressDriverCmd, "--tarball");
447     }
448
449     if ($remoteHost) {
450         push(@jscStressDriverCmd, "--remote");
451         push(@jscStressDriverCmd, $remoteHost);
452     }
453
454     if ($remoteConfigFile) {
455         push(@jscStressDriverCmd, "--remote-config-file");
456         push(@jscStressDriverCmd, $remoteConfigFile);
457     }
458
459     if ($childProcesses) {
460         push(@jscStressDriverCmd, "--child-processes");
461         push(@jscStressDriverCmd, $childProcesses);
462     }
463
464     if ($shellRunner) {
465         push(@jscStressDriverCmd, "--shell-runner");
466     }
467
468     if ($makeRunner) {
469         push(@jscStressDriverCmd, "--make-runner");
470     }
471
472     if ($memoryLimited) {
473         push(@jscStressDriverCmd, "--memory-limited");
474     }
475
476     if ($filter) {
477         push(@jscStressDriverCmd, "--filter");
478         push(@jscStressDriverCmd, $filter);
479     }
480
481     unshift @jscStressDriverCmd, wrapperPrefixIfNeeded() if shouldUseJhbuild();
482
483     # End option processing, the rest of the arguments are tests
484     push(@jscStressDriverCmd, "--");
485
486     for my $testSuite (@extraTests) {
487         push(@jscStressDriverCmd, $testSuite);
488         $hasTestsToRun = 1;
489     }
490     if (defined($ENV{"EXTRA_JSC_TESTS"})) {
491         push(@jscStressDriverCmd, $ENV{"EXTRA_JSC_TESTS"});
492         $hasTestsToRun = 1;
493     }
494
495     if (!$hasTestsToRun) {
496         exit(0);
497     }
498
499     print "Running: " . join(" ", @jscStressDriverCmd) . "\n";
500     my $result = system(@jscStressDriverCmd);
501     exit exitStatus($result) if $result;
502
503     my @jscStressFailList = readAllLines($jscStressResultsDir . "/failed");
504     @jscStressFailList = sort @jscStressFailList;
505     my $numJSCStressFailures = @jscStressFailList;
506
507     if ($numJSCStressFailures) {
508         print "\n** The following JSC stress test failures have been introduced:\n";
509         foreach my $testFailure (@jscStressFailList) {
510             print "\t$testFailure\n";
511         }
512     }
513     print "\n";
514
515     print "Results for JSC stress tests:\n";
516     printThingsFound($numJSCStressFailures, "failure", "failures", "found");
517     print "    OK.\n" if $numJSCStressFailures == 0;
518
519     print "\n";
520
521     if (defined($jsonFileName)) {
522         $jsonData{'stressTestFailures'} = \@jscStressFailList;
523     }
524
525     writeJsonDataIfApplicable();
526     exit(1) if $numJSCStressFailures;
527 }
528
529 sub readAllLines
530 {
531     my ($filename) = @_;
532     my @array = ();
533     eval {
534         open FILE, $filename or die;
535         while (<FILE>) {
536             chomp;
537             push @array, $_;
538         }
539         close FILE;
540     };
541     return @array;
542 }
543
544 sub printThingsFound
545 {
546     my ($number, $label, $pluralLabel, $verb) = @_;
547     print "    $number ";
548     if ($number == 1) {
549         print $label;
550     } else {
551         print $pluralLabel;
552     }
553     print " $verb.\n";
554 }
555
556 sub writeJsonDataIfApplicable
557 {
558     if (defined($jsonFileName)) {
559         open(my $fileHandler, ">", $jsonFileName) or die;
560         print $fileHandler "${\encode_json(\%jsonData)}\n";
561         close($fileHandler);
562     }
563 }