- add run-webkit-tests script; not working yet but the pieces are there
authordarin <darin@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sun, 5 Jun 2005 23:34:52 +0000 (23:34 +0000)
committerdarin <darin@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sun, 5 Jun 2005 23:34:52 +0000 (23:34 +0000)
        * Scripts/run-webkit-tests: Added.

        * DumpRenderTree/DumpRenderTree.m: Added.
        * DumpRenderTree/DumpRenderTree.xcode/.cvsignore: Added.
        * DumpRenderTree/DumpRenderTree.xcode/project.pbxproj: Added.
        * DumpRenderTree/DumpRenderTreePrefix.h: Added.

git-svn-id: http://svn.webkit.org/repository/webkit/trunk@9281 268f45cc-cd09-0410-ab3c-d52691b4dbfc

WebKitTools/ChangeLog
WebKitTools/DumpRenderTree/DumpRenderTree.m [new file with mode: 0644]
WebKitTools/DumpRenderTree/DumpRenderTree.xcode/.cvsignore [new file with mode: 0644]
WebKitTools/DumpRenderTree/DumpRenderTree.xcode/project.pbxproj [new file with mode: 0644]
WebKitTools/DumpRenderTree/DumpRenderTreePrefix.h [new file with mode: 0644]
WebKitTools/Scripts/run-webkit-tests [new file with mode: 0755]

index 3c78ddb963f52df6530f8436a2524361ef366890..4b6eac18116b94ad7f16d13c8ccdbb275c804d50 100644 (file)
@@ -1,3 +1,14 @@
+2005-06-05  Darin Adler  <darin@apple.com>
+
+        - add run-webkit-tests script; not working yet but the pieces are there
+
+        * Scripts/run-webkit-tests: Added.
+
+        * DumpRenderTree/DumpRenderTree.m: Added.
+        * DumpRenderTree/DumpRenderTree.xcode/.cvsignore: Added.
+        * DumpRenderTree/DumpRenderTree.xcode/project.pbxproj: Added.
+        * DumpRenderTree/DumpRenderTreePrefix.h: Added.
+
 2005-06-05  Darin Adler  <darin@apple.com>
 
         - created module, first cut at Web Kit Open Source Project scripts
@@ -8,3 +19,4 @@
         * Scripts/update-webkit: Added.
         * checkout: Added.
 
+=== creation of WebKitTools module ===
diff --git a/WebKitTools/DumpRenderTree/DumpRenderTree.m b/WebKitTools/DumpRenderTree/DumpRenderTree.m
new file mode 100644 (file)
index 0000000..7d7a047
--- /dev/null
@@ -0,0 +1,225 @@
+/*
+ * 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.
+ */
+
+#import <Foundation/NSURLRequest.h>
+#import <Foundation/NSError.h>
+
+#import <WebKit/DOMExtensions.h>
+#import <WebKit/WebCoreStatistics.h>
+#import <WebKit/WebDataSource.h>
+#import <WebKit/WebFrame.h>
+#import <WebKit/WebFrameLoadDelegate.h>
+#import <WebKit/WebFrameView.h>
+#import <WebKit/WebPreferences.h>
+#import <WebKit/WebView.h>
+
+@interface WaitUntilDoneDelegate : NSObject
+@end
+
+@interface LayoutTestController : NSObject
+@end
+
+static void dumpRenderTree(const char *filename);
+
+static volatile BOOL done;
+static WebFrame *frame;
+static BOOL waitLayoutTest;
+static BOOL dumpAsText;
+
+int main(int argc, const char *argv[])
+{
+    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
+
+    WebPreferences *preferences = [WebPreferences standardPreferences];
+    
+    NSString *standardFontFamily = [preferences standardFontFamily];
+    NSString *fixedFontFamily = [preferences fixedFontFamily];
+    NSString *serifFontFamily = [preferences serifFontFamily];
+    NSString *sansSerifFontFamily = [preferences sansSerifFontFamily];
+    NSString *cursiveFontFamily = [preferences cursiveFontFamily];
+    NSString *fantasyFontFamily = [preferences fantasyFontFamily];
+    int defaultFontSize = [preferences defaultFontSize];
+    int defaultFixedFontSize = [preferences defaultFixedFontSize];
+    int minimumFontSize = [preferences minimumFontSize];
+    
+    [preferences setStandardFontFamily:@"Times"];
+    [preferences setFixedFontFamily:@"Courier"];
+    [preferences setSerifFontFamily:@"Times"];
+    [preferences setSansSerifFontFamily:@"Helvetica"];
+    [preferences setCursiveFontFamily:@"Apple Chancery"];
+    [preferences setFantasyFontFamily:@"Papyrus"];
+    [preferences setDefaultFontSize:16];
+    [preferences setDefaultFixedFontSize:13];
+    [preferences setMinimumFontSize:9];
+
+    WebView *webView = [[WebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600)];
+    WaitUntilDoneDelegate *delegate = [[WaitUntilDoneDelegate alloc] init];
+    [webView setFrameLoadDelegate:delegate];
+    [webView setUIDelegate:delegate];
+    frame = [webView mainFrame];
+    
+    if (argc == 2 && strcmp(argv[1], "-") == 0) {
+        char filenameBuffer[2048];
+        while (fgets(filenameBuffer, sizeof(filenameBuffer), stdin)) {
+            char *newLineCharacter = strchr(filenameBuffer, '\n');
+            if (newLineCharacter) {
+                *newLineCharacter = '\0';
+            }
+            dumpRenderTree(filenameBuffer);
+            puts("#EOF");
+            fflush(stdout);
+        }
+    } else {
+        int i;
+        for (i = 1; i != argc; ++i) {
+            dumpRenderTree(argv[i]);
+        }
+    }
+    
+    [preferences setStandardFontFamily:standardFontFamily];
+    [preferences setFixedFontFamily:fixedFontFamily];
+    [preferences setSerifFontFamily:serifFontFamily];
+    [preferences setSansSerifFontFamily:sansSerifFontFamily];
+    [preferences setCursiveFontFamily:cursiveFontFamily];
+    [preferences setFantasyFontFamily:fantasyFontFamily];
+    [preferences setDefaultFontSize:defaultFontSize];
+    [preferences setDefaultFixedFontSize:defaultFixedFontSize];
+    [preferences setMinimumFontSize:minimumFontSize];
+
+    [pool release];
+    return 0;
+}
+
+static void dump(void)
+{
+    NSString *result = nil;
+    if (dumpAsText) {
+        DOMDocument *document = [frame DOMDocument];
+        if ([document isKindOfClass:[DOMHTMLDocument class]]) {
+            result = [[[(DOMHTMLDocument *)document body] innerText] stringByAppendingString:@"\n"];
+        }
+    } else {
+        result = [frame renderTreeAsExternalRepresentation];
+    }
+    if (!result) {
+        puts("error");
+    } else {
+        fputs([result UTF8String], stdout);
+    }
+    done = YES;
+}
+
+@implementation WaitUntilDoneDelegate
+
+- (void)webView:(WebView *)c locationChangeDone:(NSError *)error forDataSource:(WebDataSource *)dataSource
+{
+    if (!waitLayoutTest && [dataSource webFrame] == frame) {
+        dump();
+    }
+}
+
+- (void)webView:(WebView *)sender didFailProvisionalLoadWithError:(NSError *)error forFrame:(WebFrame *)frame
+{
+    [self webView:sender locationChangeDone:error forDataSource:[frame provisionalDataSource]];
+}
+
+- (void)webView:(WebView *)sender didFinishLoadForFrame:(WebFrame *)frame
+{
+    [self webView:sender locationChangeDone:nil forDataSource:[frame dataSource]];
+}
+
+- (void)webView:(WebView *)sender didFailLoadWithError:(NSError *)error forFrame:(WebFrame *)frame
+{
+    [self webView:sender locationChangeDone:error forDataSource:[frame dataSource]];
+}
+
+- (void)webView:(WebView *)sender windowScriptObjectAvailable:(WebScriptObject *)obj 
+{ 
+    LayoutTestController *ltc = [[LayoutTestController alloc] init];
+    [(id)obj setValue:ltc forKey:@"layoutTestController"];
+    [ltc release];
+
+}
+
+- (void)webView:(WebView *)sender runJavaScriptAlertPanelWithMessage:(NSString *)message
+{
+    printf("ALERT: %s\n", [message UTF8String]);
+}
+
+@end
+
+@implementation LayoutTestController
+
++ (BOOL)isSelectorExcludedFromWebScript:(SEL)aSelector
+{
+    if (aSelector == @selector(waitUntilDone) || aSelector == @selector(notifyDone) || aSelector == @selector(dumpAsText))
+        return NO;
+    return YES;
+}
+
+- (void)waitUntilDone 
+{
+    waitLayoutTest = YES;
+}
+
+- (void)notifyDone
+{
+    dump();
+    waitLayoutTest = NO;
+}
+
+- (void)dumpAsText
+{
+    dumpAsText = YES;
+}
+
+@end
+
+static void dumpRenderTree(const char *filename)
+{
+    CFStringRef filenameString = CFStringCreateWithCString(NULL, filename, kCFStringEncodingUTF8);
+    if (filenameString == NULL) {
+        fprintf(stderr, "can't parse filename as UTF-8\n");
+        return;
+    }
+    CFURLRef URL = CFURLCreateWithFileSystemPath(NULL, filenameString, kCFURLPOSIXPathStyle, FALSE);
+    if (URL == NULL) {
+        fprintf(stderr, "can't turn %s into a CFURL\n", filename);
+        return;
+    }
+
+    done = NO;
+    dumpAsText = NO;
+    waitLayoutTest = NO;
+
+    [frame loadRequest:[NSURLRequest requestWithURL:(NSURL *)URL]];
+    NSDate *date = [NSDate distantPast];
+    while (!done) {
+        [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:date];
+    }
+}
diff --git a/WebKitTools/DumpRenderTree/DumpRenderTree.xcode/.cvsignore b/WebKitTools/DumpRenderTree/DumpRenderTree.xcode/.cvsignore
new file mode 100644 (file)
index 0000000..fa12c5f
--- /dev/null
@@ -0,0 +1,2 @@
+*.pbxuser
+*.perspective
diff --git a/WebKitTools/DumpRenderTree/DumpRenderTree.xcode/project.pbxproj b/WebKitTools/DumpRenderTree/DumpRenderTree.xcode/project.pbxproj
new file mode 100644 (file)
index 0000000..4e7bb97
--- /dev/null
@@ -0,0 +1,238 @@
+// !$*UTF8*$!
+{
+       archiveVersion = 1;
+       classes = {
+       };
+       objectVersion = 39;
+       objects = {
+               014CEA4F0018CE4811CA2923 = {
+                       buildSettings = {
+                               COPY_PHASE_STRIP = NO;
+                               GCC_DYNAMIC_NO_PIC = NO;
+                               GCC_ENABLE_FIX_AND_CONTINUE = YES;
+                               GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
+                               GCC_OPTIMIZATION_LEVEL = 0;
+                               OPTIMIZATION_CFLAGS = "-O0";
+                               ZERO_LINK = YES;
+                       };
+                       isa = PBXBuildStyle;
+                       name = Development;
+               };
+//010
+//011
+//012
+//013
+//014
+//030
+//031
+//032
+//033
+//034
+               034768E6FF38A76511DB9C8B = {
+                       explicitFileType = "compiled.mach-o.executable";
+                       isa = PBXFileReference;
+                       path = DumpRenderTree;
+                       refType = 3;
+                       sourceTree = BUILT_PRODUCTS_DIR;
+               };
+//030
+//031
+//032
+//033
+//034
+//080
+//081
+//082
+//083
+//084
+               08FB7793FE84155DC02AAC07 = {
+                       buildSettings = {
+                       };
+                       buildStyles = (
+                               014CEA4F0018CE4811CA2923,
+                       );
+                       hasScannedForEncodings = 1;
+                       isa = PBXProject;
+                       mainGroup = 08FB7794FE84155DC02AAC07;
+                       projectDirPath = "";
+                       targets = (
+                               08FB779FFE84155DC02AAC07,
+                       );
+               };
+               08FB7794FE84155DC02AAC07 = {
+                       children = (
+                               08FB7796FE84155DC02AAC07,
+                               32A70AAB03705E1F00C91783,
+                               08FB779EFE84155DC02AAC07,
+                               9335436903D75557008635CE,
+                               9335436503D7553D008635CE,
+                               9335435F03D75502008635CE,
+                               034768E6FF38A76511DB9C8B,
+                       );
+                       isa = PBXGroup;
+                       name = DumpRenderTree;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               08FB7796FE84155DC02AAC07 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.objc;
+                       path = DumpRenderTree.m;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               08FB779EFE84155DC02AAC07 = {
+                       isa = PBXFileReference;
+                       lastKnownFileType = folder;
+                       name = Foundation.framework;
+                       path = /System/Library/Frameworks/Foundation.framework;
+                       refType = 0;
+                       sourceTree = "<absolute>";
+               };
+               08FB779FFE84155DC02AAC07 = {
+                       buildPhases = (
+                               08FB77A0FE84155DC02AAC07,
+                               08FB77A1FE84155DC02AAC07,
+                               08FB77A3FE84155DC02AAC07,
+                       );
+                       buildSettings = {
+                               FRAMEWORK_SEARCH_PATHS = "";
+                               GCC_TREAT_WARNINGS_AS_ERRORS = YES;
+                               HEADER_SEARCH_PATHS = "";
+                               INSTALL_PATH = "$(HOME)/bin";
+                               LIBRARY_SEARCH_PATHS = "";
+                               MACOSX_DEPLOYMENT_TARGET = 10.2;
+                               OTHER_CFLAGS = "";
+                               OTHER_LDFLAGS = "";
+                               PRECOMPILE_PREFIX_HEADER = YES;
+                               PREFIX_HEADER = DumpRenderTreePrefix.h;
+                               PRODUCT_NAME = DumpRenderTree;
+                               SECTORDER_FLAGS = "";
+                               WARNING_CFLAGS = "-Wall -W -Wno-unused-parameter";
+                       };
+                       dependencies = (
+                       );
+                       isa = PBXToolTarget;
+                       name = DumpRenderTree;
+                       productInstallPath = "$(HOME)/bin";
+                       productName = DumpRenderTree;
+                       productReference = 034768E6FF38A76511DB9C8B;
+               };
+               08FB77A0FE84155DC02AAC07 = {
+                       buildActionMask = 2147483647;
+                       files = (
+                               32A70AAC03705E1F00C91783,
+                       );
+                       isa = PBXHeadersBuildPhase;
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               08FB77A1FE84155DC02AAC07 = {
+                       buildActionMask = 2147483647;
+                       files = (
+                               08FB77A2FE84155DC02AAC07,
+                       );
+                       isa = PBXSourcesBuildPhase;
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               08FB77A2FE84155DC02AAC07 = {
+                       fileRef = 08FB7796FE84155DC02AAC07;
+                       isa = PBXBuildFile;
+                       settings = {
+                               ATTRIBUTES = (
+                               );
+                       };
+               };
+               08FB77A3FE84155DC02AAC07 = {
+                       buildActionMask = 2147483647;
+                       files = (
+                               08FB77A4FE84155DC02AAC07,
+                               9335436103D75502008635CE,
+                               9335436603D7553D008635CE,
+                               9335436A03D75557008635CE,
+                       );
+                       isa = PBXFrameworksBuildPhase;
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               08FB77A4FE84155DC02AAC07 = {
+                       fileRef = 08FB779EFE84155DC02AAC07;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+//080
+//081
+//082
+//083
+//084
+//320
+//321
+//322
+//323
+//324
+               32A70AAB03705E1F00C91783 = {
+                       fileEncoding = 4;
+                       isa = PBXFileReference;
+                       lastKnownFileType = sourcecode.c.h;
+                       path = DumpRenderTreePrefix.h;
+                       refType = 4;
+                       sourceTree = "<group>";
+               };
+               32A70AAC03705E1F00C91783 = {
+                       fileRef = 32A70AAB03705E1F00C91783;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+//320
+//321
+//322
+//323
+//324
+//930
+//931
+//932
+//933
+//934
+               9335435F03D75502008635CE = {
+                       isa = PBXFileReference;
+                       lastKnownFileType = wrapper.framework;
+                       path = WebKit.framework;
+                       refType = 3;
+                       sourceTree = BUILT_PRODUCTS_DIR;
+               };
+               9335436103D75502008635CE = {
+                       fileRef = 9335435F03D75502008635CE;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               9335436503D7553D008635CE = {
+                       isa = PBXFileReference;
+                       lastKnownFileType = wrapper.framework;
+                       path = WebCore.framework;
+                       refType = 3;
+                       sourceTree = BUILT_PRODUCTS_DIR;
+               };
+               9335436603D7553D008635CE = {
+                       fileRef = 9335436503D7553D008635CE;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+               9335436903D75557008635CE = {
+                       isa = PBXFileReference;
+                       lastKnownFileType = wrapper.framework;
+                       path = JavaScriptCore.framework;
+                       refType = 3;
+                       sourceTree = BUILT_PRODUCTS_DIR;
+               };
+               9335436A03D75557008635CE = {
+                       fileRef = 9335436903D75557008635CE;
+                       isa = PBXBuildFile;
+                       settings = {
+                       };
+               };
+       };
+       rootObject = 08FB7793FE84155DC02AAC07;
+}
diff --git a/WebKitTools/DumpRenderTree/DumpRenderTreePrefix.h b/WebKitTools/DumpRenderTree/DumpRenderTreePrefix.h
new file mode 100644 (file)
index 0000000..cb40968
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+ * 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.
+ */
+
+#ifdef __OBJC__
+
+#import <Foundation/Foundation.h>
+
+#endif
diff --git a/WebKitTools/Scripts/run-webkit-tests b/WebKitTools/Scripts/run-webkit-tests
new file mode 100755 (executable)
index 0000000..a3fee27
--- /dev/null
@@ -0,0 +1,230 @@
+#!/usr/bin/perl -w
+
+# Script to run the Web Kit Open Source Project layout tests.
+
+use strict;
+use IPC::Open2;
+
+# Run all the tests passed in on the command line.
+# If no tests are passed, find all the .html, .xml, and .xhtml 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
+
+# Check that we're in the right directory.
+if (! -d "WebKitTools") {
+    if (-d "../WebKitTools") {
+        chdir ".." or die;
+    }
+    if (! -d "WebKitTools") {
+        die "No WebKitTools directory found. Please run this script from the directory containing WebKitTools.\n";
+    }
+}
+
+# Check that an Xcode product directory is set.
+open PRODUCT, "defaults read com.apple.Xcode PBXProductDirectory 2> /dev/null |" or die;
+my $productDir = <PRODUCT>;
+chomp $productDir;
+close PRODUCT;
+if (!$productDir) {
+    die "No product directory set. Please set the 'Place Build Products' preference to 'Customized location' in XCode Building Preferences.\n";
+}
+
+my $tool = "$productDir/DumpRenderTree";
+
+die "can't find executable DumpRenderTree tool (looked in $productDir)\n" if !-x $tool;
+
+my $WebCoreDirectory = "WebCore";
+my $testDirectory = "$WebCoreDirectory/layout-tests";
+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 (@ARGV) {
+    for my $test (@ARGV) {
+        $test =~ s/^$testDirectory\///;
+        if ($test =~ /^\//) {
+            print "can't run test outside $testDirectory\n";
+        } elsif (-f "$testDirectory/$test") {
+            if ($test !~ /\.(html|xml|xhtml)$/) {
+                print "test $test does not have an .html extension\n";
+            } else {
+                push @tests, $test;
+            }
+        } elsif (-d "$testDirectory/$test") {
+            push @tests, map { chomp; s-^$testDirectory/--; $_; } `find -s $testDirectory/$test $findArguments`;
+        } else {
+            print "test $test not found\n";
+        }
+    }
+} else {
+    @tests = map { chomp; s-^$testDirectory/--; $_; } `find -s $testDirectory $findArguments`;
+}
+
+die "no tests to run\n" if !@tests;
+
+my %counts;
+my %tests;
+my $count;
+
+open2(\*IN, \*OUT, $tool, "-") or die;
+
+$| = 1;
+
+for my $test (@tests) {
+    next if $test eq 'results.html';
+    
+    my $base = $test;
+    $base =~ s/\.(html|xml|xhtml)$//;
+    
+    print "running $base test";
+    
+    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;
+    }
+    if (!defined $expected) {
+        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 ($actual eq $expected) {
+        print " -> succeeded\n";        
+        $result = "match";
+        unlink "$testResultsDirectory/$base-actual.txt";
+        unlink "$testResultsDirectory/$base-diffs.txt";
+    } else {
+        print " -> failed\n";        
+        $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";
+    }
+    
+    $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 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)$//;
+            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";
+            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)$//;
+            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)$//;
+            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";
+            print HTML "</tr>\n";
+        }
+        print HTML "</table>\n";
+    }
+
+    print HTML "</body>\n";
+    print HTML "</html>\n";
+    close HTML;
+    
+    system "open", $testResults;
+}