blob: 41a2591fe501798267dbe249768e0e1a5cbf3475 [file] [log] [blame]
#!/usr/bin/perl -w
# Copyright (C) 2005 Apple Computer, Inc. All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# 1. Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
# 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
# its contributors may be used to endorse or promote products derived
# from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
# DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
# Script to run the Web Kit Open Source Project layout tests.
use strict;
use IPC::Open2;
use Getopt::Long;
use FindBin;
use Cwd;
use lib $FindBin::Bin;
use webkitdirs;
# Run all the tests passed in on the command line.
# If no tests are passed, find all the .html, .xml, .xhtml (and svg) files in the test directory.
# Run each text.
# Compare against the existing file xxx-expected.txt.
# If there is a mismatch, generate xxx-actual.txt and xxx-diffs.txt.
# At the end, report:
# the number of tests that got the expected results
# the number of tests that ran, but did not get the expected results
# the number of tests that failed to run
# the number of tests that were run but had no expected results to compare against
setConfiguration();
my $productDir = productDir();
chdirWebKit();
# Argument handling
my $testSVGs = '';
my $pixelTests = '';
my $maxWidth = '';
my $maxHeight = '';
my $verbose = '';
my $quiet = '';
GetOptions('svg' => \$testSVGs,
'pixel-tests' => \$pixelTests,
'max-width' => \$maxWidth,
'max-height' => \$maxHeight,
'verbose' => \$verbose,
'quiet' => \$quiet);
my $toolname = "DumpRenderTree";
my $result = system "WebKitTools/Scripts/build-dumprendertree", @ARGV;
exit $result if $result;
if ($testSVGs) {
my $result = system "WebKitTools/Scripts/build-dumpkcanvastree", @ARGV;
exit $result if $result;
$toolname = "DumpKCanvasTree";
}
my $tool = "$productDir/$toolname";
my $imageDiffTool = "$productDir/ImageDiff";
die "can't find executable $toolname tool (looked in $productDir)\n" if !-x $tool;
die "can't find executable $imageDiffTool tool (looked in $productDir)\n" if $pixelTests && !-x $imageDiffTool;
if ($testSVGs) {
checkSVGFrameworks();
} else {
checkFrameworks();
}
my $layoutTestsName = "layout-tests";
if ($testSVGs) {
$layoutTestsName = "svg-tests";
}
my $workingDir = getcwd();
my $WebCoreDirectory = "$workingDir/WebCore";
my $testDirectory = "$WebCoreDirectory/$layoutTestsName";
my $testResultsDirectory = "/tmp/layout-test-results";
my $testResults = "$testResultsDirectory/results.html";
$ENV{DYLD_FRAMEWORK_PATH} = $productDir;
my @tests;
my $findArguments = "\\( -name resources \\! -prune \\) -or -name '*.html' -or -name '*.xml' -or -name '*.xhtml'";
if ($testSVGs) {
$findArguments = "\\( -name resources \\! -prune \\) -or -name '*.svg'";
}
my $foundTestName = 0;
for my $test (@ARGV) {
next if $test =~ /^-/;
$foundTestName = 1;
$test =~ s/^$testDirectory\///;
if ($test =~ /^\//) {
print "can't run test outside $testDirectory\n";
} elsif (-f "$testDirectory/$test") {
if ($test !~ /\.(html|xml|xhtml|svg)$/) {
print "test $test does not have a supported extension\n";
} else {
push @tests, $test;
}
} elsif (-d "$testDirectory/$test") {
push @tests, map { chomp; s-^$testDirectory/--; $_; } `find -Ls $testDirectory/$test $findArguments`;
} else {
print "test $test not found\n";
}
}
if (!$foundTestName) {
@tests = map { chomp; s-^$testDirectory/--; $_; } `find -Ls $testDirectory $findArguments`;
}
die "no tests to run\n" if !@tests;
my %counts;
my %tests;
my %imagesPresent;
my $count;
my @toolArgs;
if ($pixelTests) {
push @toolArgs, "--pixel-tests";
if ($maxWidth) {
push @toolArgs, ("--width", $maxWidth);
}
if ($maxWidth) {
push @toolArgs, ("--height", $maxWidth);
}
}
push @toolArgs, "-";
$| = 1;
open2(\*IN, \*OUT, $tool, @toolArgs) or die;
if ($pixelTests) {
open2(\*DIFFIN, \*DIFFOUT, $imageDiffTool, "") or die "unable to open $imageDiffTool\n";
}
my $column = 0;
my $lastDirectory = "";
for my $test (@tests) {
next if $test eq 'results.html';
my $base = $test;
$base =~ s/\.(html|xml|xhtml|svg)$//;
if ($verbose) {
print "running $base test";
} elsif (!$quiet) {
my $dir = $base;
$dir =~ s|/[^/]+$||;
if ($dir ne $lastDirectory) {
print "\n" unless $column == 0;
print $dir . " ";
$lastDirectory = $dir;
$column = 0;
}
print ".";
$column++;
}
my $result;
print OUT "$testDirectory/$test\n";
my $actual = "";
while (<IN>) {
last if /#EOF/;
$actual .= $_;
}
my $expected;
if (open EXPECTED, "<", "$testDirectory/$base-expected.txt") {
$expected = "";
while (<EXPECTED>) {
$expected .= $_;
}
close EXPECTED;
}
my $textDumpMatches = $expected && ($actual eq $expected);
my $actualHash = "";
my $expectedHash = "";
my $hashMatches = "";
my $actualPNG = "";
my $actualPNGSize = 0;
my $expectedPNG = "";
my $expectedPNGSize = 0;
my $diffPNG = "";
my $diffPercentage = "";
my $diffResult = "passed";
if ($pixelTests) {
while (<IN>) {
last if /#EOF/;
if (/ActualHash: ([a-f0-9]{32})/) {
$actualHash = $1;
} elsif (/BaselineHash: ([a-f0-9]{32})/) {
$expectedHash = $1;
} elsif (/Content-length: (\d+)\s*/) {
$actualPNGSize = $1;
read(IN, $actualPNG, $actualPNGSize);
}
}
if ($hashMatches = ($expectedHash eq $actualHash)) {
$diffResult = "passed";
}
if (!$hashMatches && -f "$testDirectory/$base-expected.png" && $textDumpMatches) {
$expectedPNGSize = getFilesize("$testDirectory/$base-expected.png");
open EXPECTEDPNG, "$testDirectory/$base-expected.png";
read(EXPECTEDPNG, $expectedPNG, $expectedPNGSize);
print DIFFOUT "Content-length: $actualPNGSize\n";
print DIFFOUT $actualPNG;
print DIFFOUT "Content-length: $expectedPNGSize\n";
print DIFFOUT $expectedPNG;
while (<DIFFIN>) {
last if /^error/ || /^diff:/;
if (/Content-length: (\d+)\s*/) {
read(DIFFIN, $diffPNG, $1);
}
}
if (/^diff: (.+)% (passed|failed)/) {
$diffPercentage = $1;
$diffResult = $2;
}
}
}
if ($pixelTests) {
if ($actualPNGSize != 0 && ! -f "$testDirectory/$base-expected.png") {
open EXPECTED, ">", "$testDirectory/$base-expected.png" or die "could not create $testDirectory/$base-expected.png\n";
print EXPECTED $actualPNG;
close EXPECTED;
}
# update the expected hash if the image diff said that there was no difference
if ($actualHash ne "" && ! -f "$testDirectory/$base-expected.checksum") {
open EXPECTED, ">", "$testDirectory/$base-expected.checksum" or die "could not create $testDirectory/$base-expected.checksum\n";
print EXPECTED $actualHash;
close EXPECTED;
}
}
if (!defined $expected) {
if ($verbose) {
print " -> new test\n";
}
$result = "new";
open EXPECTED, ">", "$testDirectory/$base-expected.txt" or die "could not create $testDirectory/$base-expected.txt\n";
print EXPECTED $actual;
close EXPECTED;
unlink "$testResultsDirectory/$base-actual.txt";
unlink "$testResultsDirectory/$base-diffs.txt";
} elsif ($textDumpMatches && (!$pixelTests || ($pixelTests && $diffResult eq "passed"))) {
if ($verbose) {
print " -> succeeded\n";
}
$result = "match";
unlink "$testResultsDirectory/$base-actual.txt";
unlink "$testResultsDirectory/$base-diffs.txt";
} elsif (!$textDumpMatches || ($pixelTests && $diffResult ne "passed")) {
print "\n" unless $column == 0;
print "$test -> failed\n";
$column = 0;
$result = "mismatch";
my $dir = "$testResultsDirectory/$base";
$dir =~ s|/[^/]+$||;
system "mkdir", "-p", $dir;
open ACTUAL, ">", "$testResultsDirectory/$base-actual.txt" or die;
print ACTUAL $actual;
close ACTUAL;
system "diff -u \"$testDirectory/$base-expected.txt\" \"$testResultsDirectory/$base-actual.txt\" > \"$testResultsDirectory/$base-diffs.txt\"";
if ($pixelTests && $diffPNG && $diffPNG ne "") {
$imagesPresent{$base} = 1;
open ACTUAL, ">", "$testResultsDirectory/$base-actual.png" or die;
print ACTUAL $actualPNG;
close ACTUAL;
open DIFF, ">", "$testResultsDirectory/$base-diffs.png" or die;
print DIFF $diffPNG;
close DIFF;
open DIFFHTML, ">$testResultsDirectory/$base-diffs.html" or die;
print DIFFHTML "<html>\n";
print DIFFHTML "<head>\n";
print DIFFHTML "<title>$base Image Compare</title>\n";
print DIFFHTML "<script language=\"Javascript\" type=\"text/javascript\">\n";
print DIFFHTML "var actualImageVisible = true;\n";
print DIFFHTML "function animateImage() {\n";
print DIFFHTML " var image = document.getElementById(\"animatedImage\");\n";
print DIFFHTML " var imageText = document.getElementById(\"imageText\");\n";
print DIFFHTML " if (actualImageVisible) {\n";
print DIFFHTML " image.src=\"$testDirectory/$base-expected.png\";\n";
print DIFFHTML " imageText.innerHTML = \"Expected Image\";\n";
print DIFFHTML " actualImageVisible = false;\n";
print DIFFHTML " } else {\n";
print DIFFHTML " image.src=\"$testResultsDirectory/$base-actual.png\";\n";
print DIFFHTML " imageText.innerHTML = \"Actual Image\";\n";
print DIFFHTML " actualImageVisible = true;\n";
print DIFFHTML " }\n";
print DIFFHTML " setTimeout('animateImage()',2000);\n";
print DIFFHTML "}\n";
print DIFFHTML "</script>\n";
print DIFFHTML "</head>\n";
print DIFFHTML "<body onLoad=\"animateImage();\">\n";
print DIFFHTML "<table>\n";
if ($diffPercentage) {
print DIFFHTML "<tr>\n";
print DIFFHTML "<td>Difference between images: <a href=\"$testResultsDirectory/$base-diffs.png\">$diffPercentage%</a></td>\n";
print DIFFHTML "</tr>\n";
}
print DIFFHTML "<tr>\n";
print DIFFHTML "<td id=\"imageText\" style=\"text-weight: bold;\">Actual Image</td>\n";
print DIFFHTML "</tr>\n";
print DIFFHTML "<tr>\n";
print DIFFHTML "<td><img src=\"$testResultsDirectory/$base-actual.png\" id=\"animatedImage\"></td>\n";
print DIFFHTML "</tr>\n";
print DIFFHTML "</table>\n";
print DIFFHTML "</body>\n";
print DIFFHTML "</html>\n";
}
} else {
$result = "fail";
print "\n" unless $column == 0;
print "$test -> crashed\n";
$column = 0;
close IN;
close OUT;
open2(\*IN, \*OUT, $tool, @toolArgs) or die;
}
$count += 1;
$counts{$result} += 1;
push @{$tests{$result}}, $test;
}
close IN;
close OUT;
my %text = (
match => "succeeded",
mismatch => "had incorrect layout",
new => "were new",
fail => "failed (tool did not execute successfully)",
);
print "\n";
if ($counts{match} && $counts{match} == $count) {
print "all $count test cases succeeded\n";
unlink $testResults;
} else {
for my $type ("match", "mismatch", "new", "fail") {
my $c = $counts{$type};
if ($c) {
my $t = $text{$type};
my $message;
if ($c == 1) {
$t =~ s/were/was/;
$message = sprintf "1 test case (%d%%) %s\n", 1 * 100 / $count, $t;
} else {
$message = sprintf "%d test cases (%d%%) %s\n", $c, $c * 100 / $count, $t;
}
$message =~ s-\(0%\)-(<1%)-;
print $message;
}
}
system "mkdir", "-p", $testResultsDirectory;
open HTML, ">", $testResults or die;
print HTML "<html>\n";
print HTML "<head>\n";
print HTML "<title>Layout Test Results</title>\n";
print HTML "</head>\n";
print HTML "<body>\n";
if ($counts{mismatch}) {
print HTML "<p>Tests where results did not match expected results:</p>\n";
print HTML "<table>\n";
for my $test (@{$tests{mismatch}}) {
my $base = $test;
$base =~ s/\.(html|xml|xhtml|svg)$//;
print HTML "<tr>\n";
print HTML "<td><a href=\"$testDirectory/$test\">$base</a></td>\n";
print HTML "<td><a href=\"$testDirectory/$base-expected.txt\">expected</a></td>\n";
print HTML "<td><a href=\"$base-actual.txt\">actual</a></td>\n";
print HTML "<td><a href=\"$base-diffs.txt\">diffs</a></td>\n";
if ($pixelTests) {
print HTML "<td><a href=\"$testDirectory/$base-expected.png\">expected image</a></td>\n";
if ($imagesPresent{$base}) {
print HTML "<td><a href=\"$base-diffs.html\">image diffs</a></td>\n";
}
}
print HTML "</tr>\n";
}
print HTML "</table>\n";
}
if ($counts{fail}) {
print HTML "<p>Tests that caused the DumpRenderTree tool to fail:</p>\n";
print HTML "<table>\n";
for my $test (@{$tests{fail}}) {
my $base = $test;
$base =~ s/\.(html|xml|xhtml|svg)$//;
print HTML "<tr>\n";
print HTML "<td><a href=\"$testDirectory/$test\">$base</a></td>\n";
print HTML "</tr>\n";
}
print HTML "</table>\n";
}
if ($counts{new}) {
print HTML "<p>Tests that had no expected results (probably new):</p>\n";
print HTML "<table>\n";
for my $test (@{$tests{new}}) {
my $base = $test;
$base =~ s/\.(html|xml|xhtml|svg)$//;
print HTML "<tr>\n";
print HTML "<td><a href=\"$testDirectory/$test\">$base</a></td>\n";
print HTML "<td><a href=\"$testDirectory/$base-expected.txt\">results</a></td>\n";
if ($pixelTests) {
print HTML "<td><a href=\"$testDirectory/$base-expected.png\">image</a></td>\n";
}
print HTML "</tr>\n";
}
print HTML "</table>\n";
}
print HTML "</body>\n";
print HTML "</html>\n";
close HTML;
system "open", $testResults;
}
sub getFilesize
{
my $filename = shift;
my @fileStats;
@fileStats = stat($filename);
$fileStats[7];
}