diff options
author | Ben Murdoch <benm@google.com> | 2011-06-02 12:07:03 +0100 |
---|---|---|
committer | Ben Murdoch <benm@google.com> | 2011-06-10 10:47:21 +0100 |
commit | 2daae5fd11344eaa88a0d92b0f6d65f8d2255c00 (patch) | |
tree | e4964fbd1cb70599f7718ff03e50ea1dab33890b /Tools | |
parent | 87bdf0060a247bfbe668342b87e0874182e0ffa9 (diff) | |
download | external_webkit-2daae5fd11344eaa88a0d92b0f6d65f8d2255c00.zip external_webkit-2daae5fd11344eaa88a0d92b0f6d65f8d2255c00.tar.gz external_webkit-2daae5fd11344eaa88a0d92b0f6d65f8d2255c00.tar.bz2 |
Merge WebKit at r84325: Initial merge by git.
Change-Id: Ic1a909300ecc0a13ddc6b4e784371d2ac6e3d59b
Diffstat (limited to 'Tools')
293 files changed, 9150 insertions, 2512 deletions
diff --git a/Tools/BuildSlaveSupport/build.webkit.org-config/config.json b/Tools/BuildSlaveSupport/build.webkit.org-config/config.json index 28ff304..b4a43d0 100644 --- a/Tools/BuildSlaveSupport/build.webkit.org-config/config.json +++ b/Tools/BuildSlaveSupport/build.webkit.org-config/config.json @@ -55,7 +55,7 @@ { "name": "google-windows-2", "platform": "chromium-win" }, { "name": "google-mac-2", "platform": "chromium-mac" }, { "name": "google-linux-2", "platform": "chromium-linux" }, - { "name": "google-new-tests", "platform": "mac-leopard" }, + { "name": "google-new-tests", "platform": "mac-snowleopard" }, { "name": "wincairo-1", "platform": "wincairo" }, @@ -101,6 +101,11 @@ "slavenames": ["apple-xserve-7", "test-slave"] }, { + "name": "SnowLeopard Intel Release (NRWT)", "type": "NewBuildAndTest", "builddir": "google-new-tests", + "platform": "mac-snowleopard", "configuration": "release", "architectures": ["x86_64"], + "slavenames": ["google-new-tests"] + }, + { "name": "Windows Release (Build)", "type": "Build", "builddir": "win-release", "platform": "win", "configuration": "release", "architectures": ["i386"], "triggers": ["win-release-tests", "win-release-tests-wk2"], @@ -197,11 +202,6 @@ "slavenames": ["google-linux-2"] }, { - "name": "New run-webkit-tests", "type": "NewBuildAndTest", "builddir": "google-new-tests", - "platform": "mac-leopard", "configuration": "release", "architectures": ["i386"], - "slavenames": ["google-new-tests"] - }, - { "name": "WinCairo Debug (Build)", "type": "Build", "builddir": "win-cairo-debug", "platform": "wincairo", "configuration": "debug", "architectures": ["i386"], "slavenames": ["wincairo-1"] @@ -230,7 +230,7 @@ "builderNames": ["Leopard Intel Release (Build)", "Leopard Intel Debug (Build)"] }, { "type": "PlatformSpecificScheduler", "platform": "mac-snowleopard", "branch": "trunk", "treeStableTimer": 45.0, - "builderNames": ["SnowLeopard Intel Release (Build)", "SnowLeopard Intel Leaks"] + "builderNames": ["SnowLeopard Intel Release (Build)", "SnowLeopard Intel Leaks", "SnowLeopard Intel Release (NRWT)"] }, { "type": "PlatformSpecificScheduler", "platform": "win", "branch": "trunk", "treeStableTimer": 45.0, "builderNames": ["Windows Release (Build)", "Windows Debug (Build)"] diff --git a/Tools/BuildSlaveSupport/build.webkit.org-config/master.cfg b/Tools/BuildSlaveSupport/build.webkit.org-config/master.cfg index 1beee38..61d0b42 100644 --- a/Tools/BuildSlaveSupport/build.webkit.org-config/master.cfg +++ b/Tools/BuildSlaveSupport/build.webkit.org-config/master.cfg @@ -18,6 +18,7 @@ from twisted.internet import defer import os import re import simplejson +import urllib from webkitpy.common.config import build as wkbuild from webkitpy.common.net.buildbot import BuildBot as wkbuildbot @@ -403,20 +404,32 @@ class UploadTestResults(transfer.FileUpload): class ExtractTestResults(master.MasterShellCommand): zipFile = WithProperties("public_html/results/%(buildername)s/r%(got_revision)s (%(buildnumber)s).zip") resultDirectory = WithProperties("public_html/results/%(buildername)s/r%(got_revision)s (%(buildnumber)s)") + descriptionDone = ["uploaded results"] def __init__(self): master.MasterShellCommand.__init__(self, "") + def resultDirectoryURL(self): + return self.build.getProperties().render(self.resultDirectory).replace("public_html/", "/") + "/" + def start(self): self.command = ["ditto", "-k", "-x", "-V", self.build.getProperties().render(self.zipFile), self.build.getProperties().render(self.resultDirectory)] return master.MasterShellCommand.start(self) - def finished(self, result): - url = self.build.getProperties().render(self.resultDirectory).replace("public_html/", "/") + def addCustomURLs(self): + url = self.resultDirectoryURL() + "results.html" self.addURL("view results", url) - result = master.MasterShellCommand.finished(self, result) - self.step_status.setText(["uploaded results"]) - return result + + def finished(self, result): + self.addCustomURLs() + return master.MasterShellCommand.finished(self, result) + + +class ExtractTestResultsAndLeaks(ExtractTestResults): + def addCustomURLs(self): + ExtractTestResults.addCustomURLs(self) + url = "/LeaksViewer/?url=" + urllib.quote(self.resultDirectoryURL(), safe="") + self.addURL("view leaks", url) class Factory(factory.BuildFactory): @@ -442,6 +455,7 @@ class BuildFactory(Factory): class TestFactory(Factory): TestClass = RunWebKitTests + ExtractTestResultsClass = ExtractTestResults def __init__(self, platform, configuration, architectures): Factory.__init__(self, platform, configuration, architectures, False) self.addStep(DownloadBuiltProduct) @@ -455,10 +469,11 @@ class TestFactory(Factory): self.addStep(RunPerlTests) self.addStep(ArchiveTestResults) self.addStep(UploadTestResults) - self.addStep(ExtractTestResults) + self.addStep(self.ExtractTestResultsClass) class BuildAndTestFactory(Factory): TestClass = RunWebKitTests + ExtractTestResultsClass = ExtractTestResults def __init__(self, platform, configuration, architectures): Factory.__init__(self, platform, configuration, architectures, False) if platform.startswith("chromium"): @@ -481,7 +496,7 @@ class BuildAndTestFactory(Factory): self.addStep(RunPerlTests) self.addStep(ArchiveTestResults) self.addStep(UploadTestResults) - self.addStep(ExtractTestResults) + self.addStep(self.ExtractTestResultsClass) if platform == "gtk": self.addStep(RunGtkAPITests) if platform == "qt": @@ -489,6 +504,7 @@ class BuildAndTestFactory(Factory): class BuildAndTestLeaksFactory(BuildAndTestFactory): TestClass = RunWebKitLeakTests + ExtractTestResultsClass = ExtractTestResultsAndLeaks class NewBuildAndTestFactory(BuildAndTestFactory): TestClass = NewRunWebKitTests diff --git a/Tools/BuildSlaveSupport/build.webkit.org-config/public_html/LeaksViewer/RecentBuildsLoader.js b/Tools/BuildSlaveSupport/build.webkit.org-config/public_html/LeaksViewer/RecentBuildsLoader.js index c15aef2..c847c73 100644 --- a/Tools/BuildSlaveSupport/build.webkit.org-config/public_html/LeaksViewer/RecentBuildsLoader.js +++ b/Tools/BuildSlaveSupport/build.webkit.org-config/public_html/LeaksViewer/RecentBuildsLoader.js @@ -39,7 +39,7 @@ RecentBuildsLoader.prototype = { var build = data[buildNumber]; var buildInfo = { - revision: build.sourceStamp.changes[0].rev, + revision: parseInt(build.properties.first(function(property) { return property[0] === "got_revision"; })[1], 10), leakCount: 0, url: null, }; @@ -61,7 +61,8 @@ RecentBuildsLoader.prototype = { return; if (!("view results" in step.urls)) return; - buildInfo.url = self._buildbotBaseURL + step.urls["view results"] + "/"; + var url = step.urls["view results"]; + buildInfo.url = self._buildbotBaseURL + url.replace(/\/results\.html$/, "") + "/"; } if (buildInfo.leakCount && buildInfo.url) { diff --git a/Tools/BuildSlaveSupport/build.webkit.org-config/public_html/LeaksViewer/Utilities.js b/Tools/BuildSlaveSupport/build.webkit.org-config/public_html/LeaksViewer/Utilities.js index c44848a..b1fd2b4 100644 --- a/Tools/BuildSlaveSupport/build.webkit.org-config/public_html/LeaksViewer/Utilities.js +++ b/Tools/BuildSlaveSupport/build.webkit.org-config/public_html/LeaksViewer/Utilities.js @@ -40,3 +40,11 @@ function range(n) { result[i] = i; return result; } + +Array.prototype.first = function(predicate) { + for (var i = 0; i < this.length; ++i) { + if (predicate(this[i])) + return this[i]; + } + return null; +} diff --git a/Tools/BuildSlaveSupport/win/kill-old-processes b/Tools/BuildSlaveSupport/win/kill-old-processes index f7f4423..d04b990 100755 --- a/Tools/BuildSlaveSupport/win/kill-old-processes +++ b/Tools/BuildSlaveSupport/win/kill-old-processes @@ -26,14 +26,33 @@ import os, sys
def main():
- tasksToKill = ["DumpRenderTree.exe", "DumpRenderTree_debug.exe", "testapi.exe", "testapi_debug.exe",
- "svn.exe", "httpd.exe", "cl.exe", "link.exe", "midl.exe", "devenv.exe", "perl.exe",
- "imagediff.exe", "imagediff_debug.exe", "jsc.exe", "jsc_debug.exe", "WebKit2WebProcess.exe",
- "WebKit2WebProcess_debug.exe", "WebKitTestRunner.exe", "WebKitTestRunner_debug.exe",
- "wdiff.exe", "LightTPD.exe"]
-
+ tasksToKill = [ "cl.exe",
+ "devenv.com",
+ "devenv.exe",
+ "DumpRenderTree.exe",
+ "DumpRenderTree_debug.exe",
+ "httpd.exe",
+ "imagediff.exe",
+ "imagediff_debug.exe",
+ "jsc.exe",
+ "jsc_debug.exe",
+ "LightTPD.exe",
+ "link.exe",
+ "midl.exe",
+ "perl.exe",
+ "Safari.exe",
+ "svn.exe",
+ "testapi.exe",
+ "testapi_debug.exe",
+ "VcBuildHelper.exe",
+ "wdiff.exe",
+ "WebKit2WebProcess.exe",
+ "WebKit2WebProcess_debug.exe",
+ "WebKitTestRunner.exe",
+ "WebKitTestRunner_debug.exe"]
+
for task in tasksToKill:
- os.system("taskkill /f /im " + task)
+ os.system("taskkill /t /f /im " + task)
if __name__ == '__main__':
sys.exit(main())
diff --git a/Tools/ChangeLog b/Tools/ChangeLog index 479fd41..a45d6a0 100644 --- a/Tools/ChangeLog +++ b/Tools/ChangeLog @@ -1,3 +1,3085 @@ +2011-04-19 Ojan Vafai <ojan@chromium.org> + + Fix check for whether a failure is expected to deal with + flaky tests and FAIL expectations. + * Scripts/webkitpy/layout_tests/layout_package/json_results.html: + +2011-04-19 Ojan Vafai <ojan@chromium.org> + + Reviewed by Eric Seidel. + + don't show missing text results for tests that only dump image results + https://bugs.webkit.org/show_bug.cgi?id=58931 + + * Scripts/webkitpy/layout_tests/layout_package/json_results.html: + * Scripts/webkitpy/layout_tests/layout_package/test_runner.py: + +2011-04-19 Ojan Vafai <ojan@chromium.org> + + Reviewed by Eric Seidel. + + don't show failures table if there are only new tests + https://bugs.webkit.org/show_bug.cgi?id=58929 + + * Scripts/webkitpy/layout_tests/layout_package/json_results.html: + +2011-04-19 Ojan Vafai <ojan@chromium.org> + + Reviewed by Eric Seidel. + + don't show failures table if there are only new tests + https://bugs.webkit.org/show_bug.cgi?id=58929 + + * Scripts/webkitpy/layout_tests/layout_package/json_results.html: + +2011-04-19 Ojan Vafai <ojan@chromium.org> + + Fix unittest failures from http://trac.webkit.org/changeset/84294. + + * Scripts/webkitpy/layout_tests/layout_package/test_failures_unittest.py: + * Scripts/webkitpy/layout_tests/layout_package/test_runner_unittest.py: + +2011-04-18 Ojan Vafai <ojan@chromium.org> + + Reviewed by Eric Seidel. + + switch new-run-webkit-tests to using the new results file + https://bugs.webkit.org/show_bug.cgi?id=58861 + + * Scripts/webkitpy/layout_tests/layout_package/test_failures.py: + * Scripts/webkitpy/layout_tests/layout_package/test_failures_unittest.py: + * Scripts/webkitpy/layout_tests/layout_package/test_runner.py: + +2011-04-19 Renata Hodovan <reni@webkit.org> + + Reviewed by Eric Seidel. + + Move the alignment related macros from Vector.h to new Alignment.h. + https://bugs.webkit.org/show_bug.cgi?id=56000 + + Adding the new file to the forwarding headers of Tools. + + * DumpRenderTree/ForwardingHeaders/wtf/Alignment.h: Added. + +2011-04-19 Kevin Ollivier <kevino@theolliviers.com> + + [wx] Unreviewed build fix for Win / wx 2.9 wxPython installation. + + * wx/packaging/build-win-installer.py: + * wx/packaging/wxWebKitInstaller.iss.in: + +2011-04-19 Adam Roben <aroben@apple.com> + + Skip another accelerated-compositing-sensitive test when accelerated compositing is disabled + + * Scripts/old-run-webkit-tests: Skip media/controls-without-preload.html on Windows when + accelerated compositing is disabled. + +2011-04-19 Ojan Vafai <ojan@chromium.org> + + Remove accidentally committed debug code. + * Scripts/webkitpy/layout_tests/layout_package/test_runner.py: + +2011-04-19 Brent Fulgham <bfulgham@webkit.org> + + Unreviewed build correction. + + Avoid duplicate stub implementation of test routine + for WinCairo build. + + * WebKitTestRunner/win/TestInvocationWin.cpp: Exclude + WinCairo from using this stub. + +2011-04-18 Ojan Vafai <ojan@chromium.org> + + Reviewed by Eric Seidel. + + make results file work with audio and reftests + https://bugs.webkit.org/show_bug.cgi?id=58860 + + Also fix bug with timeout tests and store a bit in the JSON + for new image tests instead of loading the image result to check if it's there. + + * Scripts/webkitpy/layout_tests/layout_package/json_results.html: + * Scripts/webkitpy/layout_tests/layout_package/test_runner.py: + +2011-04-19 Jer Noble <jer.noble@apple.com> + + Reviewed by Adam Roben. + + REGRESSION (r84206): 50 tests failing on SnowLeopard Intel Release (WebKit2 Tests) due to extra "supportsFullScreen() == true" output + https://bugs.webkit.org/show_bug.cgi?id=58890 + + Add a layoutTestController flag which controls when full screen callbacks are written to stdout. + Defaults to false. + + * WebKitTestRunner/InjectedBundle/Bindings/LayoutTestController.idl: Added dumpFullScreenCallbacks(). + * WebKitTestRunner/InjectedBundle/InjectedBundlePage.cpp: + (WTR::InjectedBundlePage::supportsFullScreen): Only write to stdout if shouldDumpFullScreenCallbacks is set. + (WTR::InjectedBundlePage::enterFullScreenForElement): Ditto. + (WTR::InjectedBundlePage::exitFullScreenForElement): Ditto. + * WebKitTestRunner/InjectedBundle/LayoutTestController.cpp: + (WTR::LayoutTestController::LayoutTestController): Initialize new ivar. + * WebKitTestRunner/InjectedBundle/LayoutTestController.h: + (WTR::LayoutTestController::dumpFullScreenCallbacks): Added. + (WTR::LayoutTestController::shouldDumpFullScreenCallbacks): Added. + +2011-04-19 Kristóf Kosztyó <Kosztyo.Kristof@stud.u-szeged.hu> + + Reviewed by Andreas Kling. + + [Qt] fast/xmlhttprequest/xmlhttprequest-nonexistent-file.html fails (DRT sideeffect) + https://bugs.webkit.org/show_bug.cgi?id=35086 + + fast/xmlhttprequest/xmlhttprequest-no-file-access.html caused + a DRT sideeffect problem, because the resetSettings didn't set + the default value of LocalContentCanAccessFileUrls. + + * DumpRenderTree/qt/DumpRenderTreeQt.cpp: + (WebCore::WebPage::resetSettings): + +2011-04-18 Zan Dobersek <zandobersek@gmail.com> + + Reviewed by Martin Robinson. + + [GTK] Need support for dumping focus rectangles in pixel results + https://bugs.webkit.org/show_bug.cgi?id=53647 + + Dump the selection rect if it has been requested. + + * DumpRenderTree/gtk/PixelDumpSupportGtk.cpp: + (createBitmapContextFromWebView): + +2011-04-18 Eric Seidel <eric@webkit.org> + + Reviewed by Adam Barth. + + test-webkitpy should run the ActiveWorkItems tests + https://bugs.webkit.org/show_bug.cgi?id=58859 + + Also make the unit tests pass. :) + + * QueueStatusServer/model/activeworkitems.py: + * QueueStatusServer/model/queue.py: + * QueueStatusServer/model/workitems.py: + +2011-04-18 Eric Seidel <eric@webkit.org> + + Reviewed by Adam Barth. + + queues.webkit.org should show trailing-days pass counts for queues + https://bugs.webkit.org/show_bug.cgi?id=58812 + + This lets us see if each bot is pulling its own weight or not. + Before I wrote this patch our suspicious was that one of the + cq bots was doing most of the work. Turns out they're actually + pretty even in their recent pass counts. + + * QueueStatusServer/handlers/queuestatus.py: + * QueueStatusServer/index.yaml: + * QueueStatusServer/templates/queuestatus.html: + +2011-04-18 Dirk Pranke <dpranke@chromium.org> + + Reviewed by Eric Seidel. + + new-run-webkit-tests: obsolete old threading code, part 1 + https://bugs.webkit.org/show_bug.cgi?id=58752 + + This patch removes support for the 'old-inline' and + 'old-threads' worker models, and deletes the corresponding code. + Now that the new code is stable, this stuff is no longer + necessary. + + * Scripts/webkitpy/layout_tests/layout_package/dump_render_tree_thread.py: Removed. + * Scripts/webkitpy/layout_tests/layout_package/message_broker.py: Removed. + * Scripts/webkitpy/layout_tests/layout_package/message_broker_unittest.py: Removed. + * Scripts/webkitpy/layout_tests/layout_package/test_runner.py: + * Scripts/webkitpy/layout_tests/run_webkit_tests.py: + * Scripts/webkitpy/layout_tests/run_webkit_tests_unittest.py: + +2011-04-18 Dirk Pranke <dpranke@chromium.org> + + Reviewed by Eric Seidel. + + new-run-webkit-tests: add an --additional-drt-flag option + https://bugs.webkit.org/show_bug.cgi?id=58680 + + NRWT has a bunch of command line flags that exist to pass + custom flags to DRT, especially on chromium. It would be nice + if there was a generic mechanism to pass through flags so we + didn't have all the custom ones. + + * Scripts/webkitpy/layout_tests/port/chromium.py: + * Scripts/webkitpy/layout_tests/port/mock_drt_unittest.py: + * Scripts/webkitpy/layout_tests/port/port_testcase.py: + * Scripts/webkitpy/layout_tests/port/test.py: + * Scripts/webkitpy/layout_tests/port/webkit.py: + * Scripts/webkitpy/layout_tests/run_webkit_tests.py: + +2011-04-05 Jer Noble <jer.noble@apple.com> + + Reviewed by Sam Weinig. + + WebKit2: WKTR should support WebKit2 full screen APIs + https://bugs.webkit.org/show_bug.cgi?id=56318 + + Respond to enterFullScreenForElement() and exitFullScreenForElement(), allowing + WKTR to test the LayoutTest/fullscreen/ tests. + + * WebKitTestRunner/InjectedBundle/InjectedBundlePage.cpp: + (WTR::InjectedBundlePage::InjectedBundlePage): Add support for WKBundlePageFullScreenClient. + (WTR::InjectedBundlePage::supportsFullScreen): Added. + (WTR::InjectedBundlePage::enterFullScreenForElement): Added. + (WTR::InjectedBundlePage::exitFullScreenForElement): Added. + * WebKitTestRunner/InjectedBundle/InjectedBundlePage.h: + * WebKitTestRunner/TestController.cpp: + (WTR::TestController::resetStateToConsistentValues): Enable the full screen preference. + +2011-04-18 Dirk Pranke <dpranke@chromium.org> + + Reviewed by Tony Chang. + + new-run-webkit-tests: remove chromium-specific relpath hack for --results-directory + https://bugs.webkit.org/show_bug.cgi?id=58388 + + * Scripts/webkitpy/layout_tests/port/chromium.py: + +2011-04-18 Evan Martin <evan@chromium.org> + + Reviewed by Eric Seidel. + + [chromium] expose title direction to webkit client + https://bugs.webkit.org/show_bug.cgi?id=58823 + + * DumpRenderTree/chromium/LayoutTestController.cpp: + (LayoutTestController::LayoutTestController): + (LayoutTestController::reset): + * DumpRenderTree/chromium/LayoutTestController.h: + (LayoutTestController::setTitleTextDirection): + Add member and setter to let us stash the title direction at load time. + + * DumpRenderTree/chromium/WebViewHost.cpp: + (WebViewHost::didReceiveTitle): + * DumpRenderTree/chromium/WebViewHost.h: + Adapt to new API; push the title into layoutTestController when we + receive it. + +2011-04-18 Dirk Pranke <dpranke@chromium.org> + + Unreviewed. + + Re-land r84112. It was rolled out in r84127 but it didn't need + to be. Only r84111 actually broke things. + + * Scripts/webkitpy/layout_tests/layout_package/test_result_writer.py: + * Scripts/webkitpy/layout_tests/run_webkit_tests_unittest.py: + +2011-04-18 Dirk Pranke <dpranke@chromium.org> + + Reviewed by Tony Chang. + + new-run-webkit-tests: don't run more processes than necessary + https://bugs.webkit.org/show_bug.cgi?id=58751 + + Previously NRWT would start up 1 process for each processor on + the machine by default, which was a waste if we were only + running a few shards of tests. + + * Scripts/webkitpy/layout_tests/layout_package/test_runner.py: + * Scripts/webkitpy/layout_tests/layout_package/test_runner2.py: + * Scripts/webkitpy/layout_tests/run_webkit_tests_unittest.py: + +2011-04-18 Ojan Vafai <ojan@chromium.org> + + Reviewed by Eric Seidel. + + include links to actual.png files for new pixel tests + https://bugs.webkit.org/show_bug.cgi?id=58831 + + Load image elements to confirm whether the files exist. + Image elements will load without being appended to the DOM. + + * Scripts/webkitpy/layout_tests/layout_package/json_results.html: + +2011-04-18 Ojan Vafai <ojan@chromium.org> + + Reviewed by Eric Seidel. + + add a zoomed view for pixel results to the new results html file + https://bugs.webkit.org/show_bug.cgi?id=58827 + + * Scripts/webkitpy/layout_tests/layout_package/json_results.html: + +2011-04-18 Ojan Vafai <ojan@chromium.org> + + Reviewed by Eric Seidel. + + add labels to results html page + https://bugs.webkit.org/show_bug.cgi?id=58803 + + -fix iframe size to be the size of the png results + -fix a bunch of aesthetic nits + -fix some incorrectly styled code + + * Scripts/webkitpy/layout_tests/layout_package/json_results.html: + +2011-04-18 Chang Shu <cshu@webkit.org> + + Reviewed by Eric Seidel. + + WebKitTestRunner needs layoutTestController.pathToLocalResource + https://bugs.webkit.org/show_bug.cgi?id=42541 + + * WebKitTestRunner/InjectedBundle/Bindings/LayoutTestController.idl: + * WebKitTestRunner/InjectedBundle/LayoutTestController.h: + * WebKitTestRunner/InjectedBundle/mac/LayoutTestControllerMac.mm: + (WTR::LayoutTestController::pathToLocalResource): + * WebKitTestRunner/InjectedBundle/qt/LayoutTestControllerQt.cpp: + (WTR::LayoutTestController::pathToLocalResource): + * WebKitTestRunner/InjectedBundle/win/LayoutTestControllerWin.cpp: + (WTR::LayoutTestController::pathToLocalResource): + +2011-04-18 Timothy Hatcher <timothy@apple.com> + + Make update-webkit-localizable-strings put WebKit/win strings in WebCore + now that all localized strings in WebKit/win use WEB_UI_STRING. + + https://webkit.org/b/58747 + + Reviewed by Dan Bernstein. + + * Scripts/update-webkit-localizable-strings: Remove the code that updated WebKit/win differently. + +2011-04-18 Patrick Gansterer <paroga@webkit.org> + + Reviewed by Adam Roben. + + [WIN] Use WCHAR instead of TCHAR + https://bugs.webkit.org/show_bug.cgi?id=58755 + + We always use the UNICODE versions of windows functions, so + the usage of TCHAR makes no sense and mixing them is bad style. + + * WinLauncher/PrintWebUIDelegate.cpp: + Also fix various style issues (including indentation and removal of ugly C-casts). + * WinLauncher/WinLauncher.cpp: + +2011-04-18 Dominic Cooney <dominicc@chromium.org> + + Reviewed by Andreas Kling. + + Add layoutTestController.shadowRoot to Qt DRT. + https://bugs.webkit.org/show_bug.cgi?id=58759 + + * DumpRenderTree/qt/LayoutTestControllerQt.cpp: + (LayoutTestController::shadowRoot): Added. + * DumpRenderTree/qt/LayoutTestControllerQt.h: + +2011-04-18 Sheriff Bot <webkit.review.bot@gmail.com> + + Unreviewed, rolling out r84111. + http://trac.webkit.org/changeset/84111 + https://bugs.webkit.org/show_bug.cgi?id=58771 + + Chromium linux layout tests are broken. (Requested by loislo2 + on #webkit). + + * Scripts/webkitpy/layout_tests/port/chromium.py: + * Scripts/webkitpy/layout_tests/port/chromium_unittest.py: + * Scripts/webkitpy/layout_tests/port/mock_drt.py: + +2011-04-18 Sheriff Bot <webkit.review.bot@gmail.com> + + Unreviewed, rolling out r84112. + http://trac.webkit.org/changeset/84112 + https://bugs.webkit.org/show_bug.cgi?id=58770 + + Chromium linux layout tests are broken. (Requested by loislo2 + on #webkit). + + * Scripts/webkitpy/layout_tests/layout_package/test_result_writer.py: + * Scripts/webkitpy/layout_tests/run_webkit_tests_unittest.py: + +2011-04-17 Daniel Bates <dbates@webkit.org> + + Reviewed by Eric Seidel and Adam Barth. + + webkit-patch land hangs if svn prompts for credentials + https://bugs.webkit.org/show_bug.cgi?id=31500 + + Prompt for username and password when using git-svn and there aren't cached SVN credentials. + + * Scripts/webkitpy/common/checkout/scm.py: + - Added mixin class SVNRepository and made both class SVN and Git inherit from it. + - Moved SVN.has_authorization_for_realm() to class SVNRepository and removed default value + for argument realm; modified call sites as needed. + - Modified AuthenticationError constructor to take optional prompt_for_password argument. + - Modified {SCM, SVN, Git}.commit_with_message() to take optional password argument. + - Modified Git._commit_on_branch() to take optional username and password argument. + - Modified Git.push_local_commits_to_server() to take optional username and password + argument and to call has_authorization_for_realm(). + * Scripts/webkitpy/common/checkout/scm_unittest.py: + - Modified SVNTest.test_commit_without_authorization() to take dummy realm argument. + - Modified SVNTest.test_not_have_authorization_for_realm() to pass realm argument to + SVN.has_authorization_for_realm(). + * Scripts/webkitpy/common/net/credentials.py: + - Modified Credentials.read_credentials() to call User.prompt_password() instead + of using getpass.getpass() directly. + * Scripts/webkitpy/common/system/user.py: + - Added User.prompt_password(). + * Scripts/webkitpy/tool/steps/commit.py: + - Modified Commit.run() to prompt for a password if needed. + +2011-04-17 Dirk Pranke <dpranke@chromium.org> + + Reviewed by Ojan Vafai. + + new-run-webkit-tests: save stderr into the layout-test-results dir + https://bugs.webkit.org/show_bug.cgi?id=58690 + + * Scripts/webkitpy/layout_tests/layout_package/test_result_writer.py: + * Scripts/webkitpy/layout_tests/run_webkit_tests_unittest.py: + +2011-04-17 Dirk Pranke <dpranke@chromium.org> + + Reviewed by Ojan Vafai. + + new-run-webkit-tests: read stderr from chromium DRT separately + https://bugs.webkit.org/show_bug.cgi?id=58708 + + * Scripts/webkitpy/layout_tests/port/chromium.py: + * Scripts/webkitpy/layout_tests/port/chromium_unittest.py: + * Scripts/webkitpy/layout_tests/port/mock_drt.py: + +2011-04-17 Patrick Gansterer <paroga@webkit.org> + + Reviewed by Adam Barth. + + Rename PLATFORM(CA) to USE(CA) + https://bugs.webkit.org/show_bug.cgi?id=58742 + + * DumpRenderTree/mac/DumpRenderTree.mm: + (resetDefaultsToConsistentValues): + +2011-04-17 Patrick Gansterer <paroga@webkit.org> + + Reviewed by Adam Barth. + + Rename PLATFORM(CG) to USE(CG) + https://bugs.webkit.org/show_bug.cgi?id=58729 + + * DumpRenderTree/PixelDumpSupport.cpp: + * DumpRenderTree/chromium/WebViewHost.cpp: + (WebViewHost::paintRect): + * DumpRenderTree/config.h: + * DumpRenderTree/win/PixelDumpSupportWin.cpp: + (createBitmapContextFromWebView): + * TestWebKitAPI/PlatformWebView.h: + * WebKitTestRunner/config.h: + * WebKitTestRunner/win/TestInvocationWin.cpp: + +2011-04-16 Patrick Gansterer <paroga@webkit.org> + + Reviewed by Eric Seidel. + + Rename PLATFORM(CAIRO) to USE(CAIRO) + https://bugs.webkit.org/show_bug.cgi?id=55192 + + * DumpRenderTree/PixelDumpSupport.cpp: + * DumpRenderTree/config.h: + * DumpRenderTree/win/PixelDumpSupportWin.cpp: + (createBitmapContextFromWebView): + * WebKitTestRunner/config.h: + +2011-04-16 Ojan Vafai <ojan@chromium.org> + + Reviewed by Eric Seidel. + + show diffs+test inline in the results page + https://bugs.webkit.org/show_bug.cgi?id=58723 + + Put each row in it's own tbody and sort based on tbodies. That way + we can append the results to the tbody inline as another table row. + + * Scripts/webkitpy/layout_tests/layout_package/json_results.html: + +2011-04-16 Ojan Vafai <ojan@chromium.org> + + Reviewed by Eric Seidel. + + handle new tests in the new results html file + https://bugs.webkit.org/show_bug.cgi?id=58715 + + * Scripts/webkitpy/layout_tests/layout_package/json_results.html: + +2011-04-15 Dirk Pranke <dpranke@chromium.org> + + Reviewed by Ojan Vafai. + + old-run-webkit-tests: save the list of tests actually run to a file + https://bugs.webkit.org/show_bug.cgi?id=58692 + + * Scripts/old-run-webkit-tests: + +2011-04-15 Dirk Pranke <dpranke@chromium.org> + + Reviewed by Ojan Vafai. + + fix MockFileSystem.abspath() on windows + https://bugs.webkit.org/show_bug.cgi?id=58713 + + The existing code was borked on Windows if a path was passed + in using a drive letter (e.g., "d:\foo.txt"), and would go + into an infinite recursive loop. While win paths shouldn't + normally be passed into the mock filesystem, this just + bulletproofs things a bit (note that "/foo.txt" is considered + an absolute path on windows python as well. + + * Scripts/webkitpy/common/system/filesystem_mock.py: + +2011-04-15 Ojan Vafai <ojan@chromium.org> + + Reviewed by Eric Seidel. + + show stderr files and httpd log files + https://bugs.webkit.org/show_bug.cgi?id=58714 + + * Scripts/webkitpy/layout_tests/layout_package/json_results.html: + * Scripts/webkitpy/layout_tests/layout_package/test_runner.py: + +2011-04-15 Shishir Agrawal <shishir@chromium.org> + + Reviewed by James Robinson. + + Add a flag to guard Page Visibility API changes. + https://bugs.webkit.org/show_bug.cgi?id=58464 + + * Scripts/build-webkit: + +2011-04-15 Chang Shu <cshu@webkit.org> + + Reviewed by Alexey Proskuryakov. + + When a message with url embedded is added to console, the "file:" scheme + and path should be stripped. + https://bugs.webkit.org/show_bug.cgi?id=58665 + + * WebKitTestRunner/InjectedBundle/InjectedBundlePage.cpp: + (WTR::lastFileURLPathComponent): + (WTR::InjectedBundlePage::willAddMessageToConsole): + +2011-04-15 Jeff Miller <jeffm@apple.com> + + Reviewed by Sam Weinig. + + Add takeFocus callback to WKPageUIClient + https://bugs.webkit.org/show_bug.cgi?id=58686 + + Add empty WKPageUIClient entries for the takeFocus callback in the MiniBrowser and WebKitTestRunner. + + * MiniBrowser/mac/BrowserWindowController.m: + (-[BrowserWindowController awakeFromNib]): Added empty takeFocus entry. + * MiniBrowser/win/BrowserView.cpp: + (BrowserView::create): Added empty takeFocus entry. + * WebKitTestRunner/TestController.cpp: + (WTR::TestController::createOtherPage): Added empty takeFocus entry. + (WTR::TestController::initialize): Added empty takeFocus entry. + +2011-04-15 Ojan Vafai <ojan@chromium.org> + + Reviewed by Eric Seidel. + + only show pretty-diff/wdiff if they were generated + https://bugs.webkit.org/show_bug.cgi?id=58682 + + * Scripts/webkitpy/layout_tests/layout_package/json_results.html: + * Scripts/webkitpy/layout_tests/layout_package/test_runner.py: + * Scripts/webkitpy/layout_tests/port/base.py: + +2011-04-15 Andreas Kling <kling@webkit.org> + + Reviewed by Antonio Gomes. + + [Qt] DRT: Default custom policy delegate decision should be Ignore. + + If layoutTestController.setCustomPolicyDelegate() is called with only + one argument, the second ("permissive") should default to false. + + * DumpRenderTree/qt/LayoutTestControllerQt.h: + +2011-04-15 Ojan Vafai <ojan@chromium.org> + + Reviewed by Eric Seidel. + + fix path to layout test in new results file + https://bugs.webkit.org/show_bug.cgi?id=58618 + + * Scripts/webkitpy/layout_tests/layout_package/json_results.html: + * Scripts/webkitpy/layout_tests/layout_package/test_runner.py: + +2011-04-15 Ojan Vafai <ojan@chromium.org> + + Reviewed by Eric Seidel. + + fix sorting in new results file + https://bugs.webkit.org/show_bug.cgi?id=58616 + + -Fix the custom sort to return -1, 0, 1 instead of true/false. + -Secondary sort by test name when sort values are equal. + -Sort by test name by default. + + * Scripts/webkitpy/layout_tests/layout_package/json_results.html: + +2011-04-15 Dmitry Lomov <dslomov@google.com> + + Reviewed by David Levin. + + check-webkit-style shouldn't complain about not including a primary header file + if none exists + https://bugs.webkit.org/show_bug.cgi?id=39514 + + * Scripts/webkitpy/style/checkers/cpp.py: + * Scripts/webkitpy/style/checkers/cpp_unittest.py: + +2011-04-15 Eric Seidel <eric@webkit.org> + + Reviewed by Mihai Parparita. + + queues.webkit.org should display when a bot last rebooted + https://bugs.webkit.org/show_bug.cgi?id=58562 + + There is more repeated code here than I would like. I fear + my django-fu isn't quite up to snuff. + + * QueueStatusServer/handlers/queuestatus.py: + * QueueStatusServer/templates/queuestatus.html: + +2011-04-14 Alok Priyadarshi <alokp@chromium.org> + + Reviewed by Adam Barth. + + Remove dependency on chromium skia::PlatformCanvas + https://bugs.webkit.org/show_bug.cgi?id=57563 + + Fixed compile error on Mac when using Core Graphics. + + * DumpRenderTree/chromium/WebViewHost.cpp: + (WebViewHost::paintRect): + +2011-04-14 Alok Priyadarshi <alokp@chromium.org> + + Reviewed by James Robinson. + + Remove dependency on chromium skia::PlatformCanvas + https://bugs.webkit.org/show_bug.cgi?id=57563 + + * DumpRenderTree/chromium/TestShell.cpp: + (makeCanvasOpaque): + (TestShell::dumpImage): + * DumpRenderTree/chromium/TestShell.h: + * DumpRenderTree/chromium/WebThemeControlDRTWin.cpp: + (WebThemeControlDRTWin::WebThemeControlDRTWin): + (WebThemeControlDRTWin::draw): + (WebThemeControlDRTWin::drawTextField): + (WebThemeControlDRTWin::drawProgressBar): + * DumpRenderTree/chromium/WebThemeControlDRTWin.h: + * DumpRenderTree/chromium/WebViewHost.cpp: + (WebViewHost::canvas): + * DumpRenderTree/chromium/WebViewHost.h: + +2011-04-14 Keith Kyzivat <keith.kyzivat@nokia.com> + + Reviewed by Laszlo Gombos. + + [Qt] Add -maximize flag to QtTestBrowser and MiniBrowser + https://bugs.webkit.org/show_bug.cgi?id=58007 + + Adds flag to start the test browsers maximized. + Symbian started maximized on QtTestBrowser - made MiniBrowser follow + suit. + Also fixes some ToggleFullScreen issues so that prior window state is + restored. + + * MiniBrowser/qt/BrowserWindow.cpp: + (BrowserWindow::BrowserWindow): + (BrowserWindow::toggleFullScreenMode): + * MiniBrowser/qt/MiniBrowserApplication.cpp: + (MiniBrowserApplication::handleUserOptions): + * MiniBrowser/qt/MiniBrowserApplication.h: + (WindowOptions::WindowOptions): + * QtTestBrowser/launcherwindow.cpp: + (LauncherWindow::init): + (LauncherWindow::toggleFullScreenMode): + * QtTestBrowser/launcherwindow.h: + (WindowOptions::WindowOptions): + * QtTestBrowser/main.cpp: + (LauncherApplication::handleUserOptions): + +2011-04-14 Ojan Vafai <ojan@chromium.org> + + Reviewed by Eric Seidel. + + add checkbox to only show unexpected results to new results file + https://bugs.webkit.org/show_bug.cgi?id=58606 + + * Scripts/webkitpy/layout_tests/layout_package/json_results.html: + +2011-04-13 Brent Fulgham <bfulgham@webkit.org> + + Reviewed by Martin Robinson. + + [WinCairo] Implement ImageDiff Logic. + http://bugs.webkit.org/show_bug.cgi?id=58486 + + * DumpRenderTree/win/ImageDiffCairo.cpp: Added. + (strtof): + (readFromData): + (createImageFromStdin): + (releaseMallocBuffer): + (createDifferenceImage): + (imageHasAlpha): + (writeToData): + (main): + * DumpRenderTree/win/ImageDiff.vcproj: Updated for new + ImageDiffCairo.cpp (excluding from Apple builds). + * DumpRenderTree/win/ImageDiffDebugCairoCFLite.vsprops: Use + new ImageDiffWinCairoCommon.vsprops file. + * DumpRenderTree/win/ImageDiffReleaseCairoCFLite.vsprops: Use + new ImageDiffWinCairoCommon.vsprops file. + * DumpRenderTree/win/ImageDiffWinCairoCommon.vsprops: Added. + * Scripts/old-run-webkit-tests: Make sure proper executable + is built and executed for WinCairo port. + +2011-04-14 Ojan Vafai <ojan@chromium.org> + + Reviewed by Eric Seidel. + + only show expected failure type for ports that use an expectations file + https://bugs.webkit.org/show_bug.cgi?id=58588 + + * Scripts/webkitpy/layout_tests/layout_package/json_results.html: + * Scripts/webkitpy/layout_tests/layout_package/test_runner.py: + +2011-04-14 Eric Seidel <eric@webkit.org> + + Reviewed by Adam Barth. + + commit-queue fails to catch IOError when results.html is missing + https://bugs.webkit.org/show_bug.cgi?id=58589 + + * Scripts/webkitpy/tool/commands/queues.py: + * Scripts/webkitpy/tool/commands/queues_unittest.py: + +2011-04-14 Kevin Ollivier <kevino@theolliviers.com> + + [wx] Unreviewed build fix for Mac installation script. + + * wx/packaging/build-mac-installer.py: + +2011-04-14 Ojan Vafai <ojan@chromium.org> + + Reviewed by Tony Chang. + + sort columns in the new json_results.html file + https://bugs.webkit.org/show_bug.cgi?id=58581 + + Also fix padding on TDs and the path to layout tests. + + * Scripts/webkitpy/layout_tests/layout_package/json_results.html: + +2011-04-14 Eric Seidel <eric@webkit.org> + + Reviewed by Dimitri Glazkov. + + queues.webkit.org should display when a bot last passed a patch + https://bugs.webkit.org/show_bug.cgi?id=58546 + + I am suspicious that some of our commit-queue instances are never + actually passing anything. + + This will let us know if those bots are never passing patches. + + * QueueStatusServer/handlers/queuestatus.py: + * QueueStatusServer/index.yaml: + * QueueStatusServer/templates/queuestatus.html: + +2011-04-14 Dirk Pranke <dpranke@chromium.org> + + Reviewed by Adam Roben. + + REGRESSION (r83764): webkitpy.layout_tests.port.chromium_win_unittest.ChromiumWinTest.test_default_worker_model fails on apple-windows-13 + https://bugs.webkit.org/show_bug.cgi?id=58545 + + Remove platform-specific overrides; the default behavior should + be working everywhere now, I think. + + * Scripts/webkitpy/layout_tests/port/chromium_win.py: + * Scripts/webkitpy/layout_tests/port/mac.py: + +2011-04-14 Eric Seidel <eric@webkit.org> + + Reviewed by Adam Barth. + + commit-queues are hitting an exception trying to land when the tree is red + https://bugs.webkit.org/show_bug.cgi?id=58558 + + Just an un-tested (and thus broken) code path from yesterday's changes. + + * Scripts/webkitpy/common/net/layouttestresults.py: + * Scripts/webkitpy/common/net/layouttestresults_unittest.py: + * Scripts/webkitpy/tool/commands/queues.py: + * Scripts/webkitpy/tool/commands/queues_unittest.py: + +2011-04-14 Kevin Ollivier <kevino@theolliviers.com> + + [wx] Unreviewed build fixes for wxMSW and wx 2.9.1.1. + + * DumpRenderTree/wx/LayoutTestControllerWx.cpp: + (LayoutTestController::shadowRoot): + * wx/build/wxpresets.py: + +2011-04-14 Victoria Kirst <vrk@google.com> + + Reviewed by James Robinson. + + [chromium] Failing GPU video tests + https://bugs.webkit.org/show_bug.cgi?id=57926 + + Added/updated GPU directory names for rebaseline tool. + + * Scripts/webkitpy/layout_tests/rebaseline_chromium_webkit_tests.py: + +2011-04-13 Daniel Bates <dbates@rim.com> + + Reviewed by Adam Barth. + + Perl unit test removeEOL.pl should print test case name on failure + https://bugs.webkit.org/show_bug.cgi?id=58513 + + * Scripts/webkitperl/VCSUtils_unittest/removeEOL.pl: Pass $title as + second argument of Test::Simple::ok(). + +2011-04-13 Kent Tamura <tkent@chromium.org> + + Reviewed by Eric Seidel. + + gdb-safari should pass arguments to safari. + https://bugs.webkit.org/show_bug.cgi?id=58439 + + We can do: + gdb-safari --debug LayoutTests/.../foo.html + + * Scripts/gdb-safari: Passing @ARGV to Safari via gdb --arg. + +2011-04-13 Dirk Pranke <dpranke@chromium.org> + + Unreviewed, build fix. + https://bugs.webkit.org/show_bug.cgi?id=52763 + + r83799 broke test-webkitpy because it assumed we always have + access to a real filesystem (we don't during the unit tests). + Stubbing out the copy for now but we might need a better + solution at some point. + + * Scripts/webkitpy/layout_tests/layout_package/test_runner.py: + +2011-04-13 Dirk Pranke <dpranke@chromium.org> + + Reviewed by Tony Chang. + + new-run-webkit-tests --run-singly option is busted + https://bugs.webkit.org/show_bug.cgi?id=55909 + + Python's broken lexical scoping strikes again :(. + + * Scripts/webkitpy/layout_tests/layout_package/worker_mixin.py: + * Scripts/webkitpy/layout_tests/run_webkit_tests_unittest.py: + +2011-04-13 Ojan Vafai <ojan@chromium.org> + + Reviewed by Eric Seidel. + + generated unexpected_results.html from unexpected_results.json + https://bugs.webkit.org/show_bug.cgi?id=52763 + + Eventually, we'll merge this with results.html and have a single richer results page. + For now, I just want to get something checked in that we can iterate on. + + * Scripts/webkitpy/layout_tests/layout_package/json_results.html: Added. + * Scripts/webkitpy/layout_tests/layout_package/test_runner.py: + +2011-04-13 Eric Seidel <eric@webkit.org> + + Reviewed by Adam Barth. + + Up the failure limit to allow the commit-queue to actually land when the tree is red + https://bugs.webkit.org/show_bug.cgi?id=58499 + + This change increases the --exit-after-N-failures limit used by the commit-queue + from 1 to 10. This will cause the code added in bug 58494 to actually get + exercised and the queues should start being able to land when the trees are red. + + When testing I found that test_runtests_leopard_commit_queue_hack_command was the + only unit test to actually detect this change! Since we don't actually + run on leopard anymore, I removed the hack code and repurposed the test. + + * Scripts/webkitpy/tool/bot/commitqueuetask.py: + * Scripts/webkitpy/tool/steps/runtests.py: + * Scripts/webkitpy/tool/steps/steps_unittest.py: + +2011-04-13 Eric Seidel <eric@webkit.org> + + Reviewed by Adam Barth. + + commit-queue should be able to land when tree is red + https://bugs.webkit.org/show_bug.cgi?id=58494 + + There is some yak hair on my hands, I will admit. + + This change is mostly about adding an ExpectedFailures + class to track when the bots are red and we should be + ignoring failures when landing from the commit-queue. + + However, to make intelligent decisions about patches we + need to know whether the run hit the --exit-after-N-failures limit + or not. Right now that information is not saved off in results.html + so we have to pull the information from RunTests. + + I've plumbed the --exit-after-N-failures information into + LayoutTestResults for now to make the ExpectedFailures code cleaner. + + As a result of adding all these additional calls to delegate.layout_test_results() + I broke some of our flaky test detection tests and had to re-write them + to not depend on the number of layout_test_results code. + + At the same time I updated the commit-queue to use the newer filesystem + API (to allow us to use MockFileSystem) which required further changes + to the layout tests. Changes were required in either case, since + we're now calling layout_test_results() in more cases, which previously + would try and hit the disk (until I moved it to use tool.filesystem). + + I should note that *all* of this code is disabled for now, since our + --exit-after-N-failures limit is currently 1! (Thus were always in the + case where we can't actually tell if the layout test results are legit.) + I will up that limit in a second patch (which may require a couple more unit test tweaks). + + * Scripts/webkitpy/common/net/layouttestresults.py: + * Scripts/webkitpy/tool/bot/commitqueuetask.py: + * Scripts/webkitpy/tool/bot/commitqueuetask_unittest.py: + * Scripts/webkitpy/tool/bot/expectedfailures.py: Added. + * Scripts/webkitpy/tool/bot/expectedfailures_unittest.py: Added. + * Scripts/webkitpy/tool/commands/queues.py: + * Scripts/webkitpy/tool/commands/queues_unittest.py: + * Scripts/webkitpy/tool/commands/queuestest.py: + * Scripts/webkitpy/tool/steps/runtests.py: + +2011-04-13 Brent Fulgham <bfulgham@webkit.org> + + Unreviewed build correction. + + * TestWebKitAPI/PlatformWebView.h: Limit include of + <CoreGraphics/CGGeometry> to PLATFORM(CG) users. + +2011-04-13 Mihai Parparita <mihaip@chromium.org> + + Reviewed by Eric Seidel. + + [NRWT] Rename --baseline-search-patch to --additional-platform-directory to match ORWT + https://bugs.webkit.org/show_bug.cgi?id=58489 + + r83743 added --additional-platform-directory to old-run-webkit-tests, + rename the equivalent flag in new-run-webkit-tests to be consistent. + + * Scripts/webkitpy/layout_tests/port/base.py: + * Scripts/webkitpy/layout_tests/port/base_unittest.py: + * Scripts/webkitpy/layout_tests/run_webkit_tests.py: + * Scripts/webkitpy/layout_tests/run_webkit_tests_unittest.py: + +2011-04-13 Mihai Parparita <mihaip@chromium.org> + + Reviewed by Eric Seidel. + + Rebaseline queue server + https://bugs.webkit.org/show_bug.cgi?id=57891 + + Adds a simple rebaseline queue server (meant to run at + http://rebaseline-queue.appspot.com/). It presents a list of all (NRWT) + builders and their failing tests, and allows those tests to be added to + a per-builer rebaseline queue. + + A subsequent change will add a mode to NRWT (and/or a wrapper script) + for pulling the tests to be rebaselined from the server and running them + with --reset-results (the initial use-case is for the GPU hardware bots, + which do not have checked-in baselines, therefore there is no need for a + check-in step yet). + + * RebaselineQueueServer/app.yaml: Added. + * RebaselineQueueServer/handlers/__init__.py: Added. + * RebaselineQueueServer/handlers/builderqueue.py: Added. + * RebaselineQueueServer/handlers/pages.py: Added. + * RebaselineQueueServer/index.yaml: Added. + * RebaselineQueueServer/main.py: Added. + * RebaselineQueueServer/model/__init__.py: Added. + * RebaselineQueueServer/model/queueentry.py: Added. + * RebaselineQueueServer/static/builder-frame-empty.html: Added. + * RebaselineQueueServer/static/styles.css: Added. + * RebaselineQueueServer/templates/builder-picker.html: Added. + * RebaselineQueueServer/templates/builder-queue-edit.html: Added. + * RebaselineQueueServer/templates/builder-queue-list.html: Added. + * RebaselineQueueServer/templates/home.html: Added. + +2011-04-13 Dirk Pranke <dpranke@chromium.org> + + Reviewed by Mihai Parparita. + + nrwt: enable multiple processes by default on Chromium Win. + https://bugs.webkit.org/show_bug.cgi?id=55163 + + Re-land r79268; it should be more stable now and will hopefully + work. + + * Scripts/webkitpy/layout_tests/port/chromium_win.py: + * Scripts/webkitpy/layout_tests/port/chromium_win_unittest.py: + +2011-04-13 Dirk Pranke <dpranke@chromium.org> + + Reviewed by Ojan Vafai. + + new-run-webkit-tests: configure logging in child processes properly + https://bugs.webkit.org/show_bug.cgi?id=58296 + + Logging propagated properly from manager to worker processes on + Unix but not on Windows; this fixes that. + + * Scripts/webkitpy/layout_tests/layout_package/manager_worker_broker.py: + * Scripts/webkitpy/layout_tests/layout_package/manager_worker_broker_unittest.py: + +2011-04-13 Dirk Pranke <dpranke@chromium.org> + + Reviewed by Ojan Vafai. + + new-run-webkit-tests: suppress extraneous pretty patch warnings + https://bugs.webkit.org/show_bug.cgi?id=58295 + + NRWT wasn't being careful about when it logged messages from + PrettyPatch not being available; it should only log during + check_build(), and be silent otherwise. This was causing us to + get multiple errors at runtime, which was confusing. + + * Scripts/webkitpy/layout_tests/port/base.py: + * Scripts/webkitpy/layout_tests/port/base_unittest.py: + * Scripts/webkitpy/layout_tests/port/chromium.py: + +2011-04-13 Dirk Pranke <dpranke@chromium.org> + + Reviewed by Jian Li. + + add chromium-linux-x86_64 to rebaseline-chromium-webkit-tests + https://bugs.webkit.org/show_bug.cgi?id=58461 + + * Scripts/webkitpy/layout_tests/rebaseline_chromium_webkit_tests.py: + +2011-04-13 Tony Chang <tony@chromium.org> + + Unreviewed, fix NRWT. Stack: + + return super(ChromiumPort, self).results_directory(self) + TypeError: results_directory() takes exactly 1 argument (2 given) + + * Scripts/webkitpy/layout_tests/port/chromium.py: + +2011-04-13 Adam Roben <aroben@apple.com> + + Teach ORWT about extra platform-specific directories to be searched before the default ones + + Fixes <http://webkit.org/b/58446> ORWT needs a way to look in a user-specified directory for + platform-specific results + + Reviewed by Anders Carlsson. + + * Scripts/old-run-webkit-tests: + (top-level): Added @additionalPlatformDirectories and hooked up + --additional-platform-directories to populate it. + (buildPlatformResultHierarchy): Prepend the additional platform directories to the default + list (after filtering out any of the additional directories that don't exist). + +2011-04-13 Lucas Forschler <lforschler@apple.com> + + Reviewed by Adam Roben. + + Add the /T command to taskkill.exe. + This will kill spawned child processes. + + * BuildSlaveSupport/win/kill-old-processes: + +2011-04-13 Lucas Forschler <lforschler@apple.com> + + Reviewed by Adam Roben. + + Sort kill list alphabeticaly. + Fixed capitalization on VcBuildHelper. + + * BuildSlaveSupport/win/kill-old-processes: + +2011-04-13 Lucas Forschler <lforschler@apple.com> + + Reviewed by Adam Roben. + + https://bugs.webkit.org/show_bug.cgi?id=58384 + Update kill-old-processes to include a few new ones. + + * BuildSlaveSupport/win/kill-old-processes: + +2011-04-13 Gustavo Noronha Silva <gns@gnome.org> + + Reviewed by Martin Robinson. + + [GTK] PluginPackage should check whether a plugin mixes GTK+ 2 and 3 symbols itself + https://bugs.webkit.org/show_bug.cgi?id=58297 + + Do not disable flash specifically when built with GTK+ 3 - + PluginPackage should do the right thing while loading plugins. + + * GtkLauncher/main.c: + (main): + +2011-04-12 Kent Tamura <tkent@chromium.org> + + Reviewed by Dimitri Glazkov. + + [Chromium] Add WebSettings::setValidationMessageTimerMagnification() + https://bugs.webkit.org/show_bug.cgi?id=57426 + + * DumpRenderTree/chromium/WebPreferences.cpp: + (WebPreferences::applyTo): Disable the validation message timer. + +2011-04-12 James Kozianski <koz@chromium.org> + + Unreviewed. + + Adding myself to committers.py. + + * Scripts/webkitpy/common/config/committers.py: + +2011-04-12 Brent Fulgham <bfulgham@webkit.org> + + Unreviewed build correction for WinCairo bot after r83639. + https://bugs.webkit.org/show_bug.cgi?id=51790 + + Correct typo for the new "update-webkit-wincairo-libs" script. + + * Scripts/build-webkit: Incorrectly calling the + update-webkit-cairo-libs which does not exist. + +2011-04-12 Alice Liu <alice.liu@apple.com> + + Reviewed by Jon Honeycutt. + + A change that should have been part of http://trac.webkit.org/changeset/83628 + + * DumpRenderTree/win/DumpRenderTree.cpp: + (resetDefaultsToConsistentValues): Setting should be off for most tests. Reset to false. + +2011-04-12 Dirk Pranke <dpranke@chromium.org> + + Reviewed by Tony Chang. + + new-run-webkit-tests: --results-directory is relative to builddir, not $PWD + https://bugs.webkit.org/show_bug.cgi?id=58272 + + NRWT was interpreting the --results-directory cmd line arg as + relative to the build directory, not the current working + directory (ORWT uses the latter, which is much more intuitive). + + This patch fixes the base case, but includes an override for + Chromium that is needed until the bots can be updated. + + * Scripts/webkitpy/layout_tests/port/base.py: + * Scripts/webkitpy/layout_tests/port/base_unittest.py: + * Scripts/webkitpy/layout_tests/port/chromium.py: + * Scripts/webkitpy/layout_tests/port/port_testcase.py: + * Scripts/webkitpy/layout_tests/port/test.py: + * Scripts/webkitpy/layout_tests/port/webkit.py: + * Scripts/webkitpy/layout_tests/run_webkit_tests.py: + * Scripts/webkitpy/layout_tests/run_webkit_tests_unittest.py: + +2011-04-12 Philippe Normand <pnormand@igalia.com> + + Unreviewed, roll out r83621 as it broke the GTK build. + + [GTK] arguments passed to build-jsc and build-webkit scripts are not taken into account + https://bugs.webkit.org/show_bug.cgi?id=58333 + + * Scripts/build-jsc: + * Scripts/build-webkit: + +2011-04-12 Carl Lobo <carllobo@gmail.com> and Brent Fulgham <bfulgham@webkit.org> + + Reviewed by Adam Roben. + + Patch to download the WinCairo dependancies as part of build-webkit. + https://bugs.webkit.org/show_bug.cgi?id=51790 + + This patch downloads the dependancies from + http://idisk.mac.com/bfulgham-Public/WinCairoRequirements.zip + checking the modification timestamp etc. + + * Tools/Scripts/build-webkit + * Tools/Scripts/update-webkit: Modified to understand the --wincairo + flag, and to update WinCairo dependencies when used. + * Tools/Scripts/update-webkit-cairo-libs: added + * Tools/Scripts/update-webkit-dependency: added + * Tools/Scripts/update-webkit-auxiliary-libs + +2011-04-12 Jeff Miller <jeffm@apple.com> + + Reviewed by Adam Roben. + + WebKit2: Pressing Tab in Web Inspector's console does not cycle through completion options + https://bugs.webkit.org/show_bug.cgi?id=56020 + + Don't call TranslateMessage() in the MiniBrowser or TestWebKitAPI for key messages destined for a WebKit2 view, + since WebKit will do this for us. If we didn't do this, TranslateMessage() would be called twice, + which would generate two characters for every keypress (for example). I didn't bother doing this for + WebKitTestRunner, since it doesn't get any WM_KEYDOWN events. + + Add new WebKit2/TranslateMessageGeneratesWMChar test to test expected TranslateMessage() behavior. + + * MiniBrowser/win/main.cpp: + (shouldTranslateMessage): Added. + (_tWinMain): Don't call TranslateMessage() unless shouldTranslateMessage() says to. + * TestWebKitAPI/PlatformUtilities.h: Added shouldTranslateMessage() on Windows. + * TestWebKitAPI/PlatformWebView.h: Added simulateAKeyDown(). + * TestWebKitAPI/Tests/WebKit2/win/TranslateMessageGeneratesWMChar.cpp: Added. + (TestWebKitAPI::didNotHandleKeyEventCallback): Added. + (TestWebKitAPI::runAndWatchForWMChar): Added. + (TestWebKitAPI::TEST): Added. + * TestWebKitAPI/win/PlatformUtilitiesWin.cpp: + (TestWebKitAPI::Util::run): Don't call TranslateMessage() unless shouldTranslateMessage() says to. + (TestWebKitAPI::Util::shouldTranslateMessage): Added. + * TestWebKitAPI/win/PlatformWebViewWin.cpp: + (TestWebKitAPI::PlatformWebView::simulateAKeyDown): Added. + * TestWebKitAPI/win/TestWebKitAPI.vcproj: Added TranslateMessageGeneratesWMChar.cpp. + +2011-04-12 Dirk Pranke <dpranke@chromium.org> + + Reviewed by Tony Chang. + + new-run-webkit-tests: update code to use port.results_directory() instead of options.results_directory + https://bugs.webkit.org/show_bug.cgi?id=58290 + + This is some preliminary refactoring for bug 58272. + + * Scripts/webkitpy/layout_tests/layout_package/single_test_runner.py: + * Scripts/webkitpy/layout_tests/layout_package/test_result_writer.py: + * Scripts/webkitpy/layout_tests/layout_package/test_runner.py: + * Scripts/webkitpy/layout_tests/layout_package/worker_mixin.py: + * Scripts/webkitpy/layout_tests/port/test.py: + * Scripts/webkitpy/layout_tests/port/chromium.py: + * Scripts/webkitpy/layout_tests/port/base.py: + * Scripts/webkitpy/layout_tests/run_webkit_tests.py: + +2011-04-12 Dirk Pranke <dpranke@chromium.org> + + Reviewed by Eric Seidel. + + webkitpy: fix mock_filesystem abspath to handle relative paths + and add filesystem.chdir() and filesystem.getcwd() to be able + to test this and mock it out. + + https://bugs.webkit.org/show_bug.cgi?id=58288 + + * Scripts/webkitpy/common/system/filesystem.py: + * Scripts/webkitpy/common/system/filesystem_mock.py: + * Scripts/webkitpy/common/system/filesystem_unittest.py: + +2011-04-12 Alice Liu <alice.liu@apple.com> + + Reviewed by Sam Weinig. + + https://bugs.webkit.org/show_bug.cgi?id=58292 + Provide new setting to allow site icon loading despite disabling automatic image loading in general. + + * DumpRenderTree/mac/DumpRenderTree.mm: + (resetDefaultsToConsistentValues): Setting should be off for most tests. Reset to false. + +2011-04-12 Thouraya ANDOLSI <thouraya.andolsi@st.com> + + Reviewed by Eric Seidel. + + [Qt] Enable JIT build for SH4 platforms. + https://bugs.webkit.org/show_bug.cgi?id=58317 + + + * DumpRenderTree/qt/DumpRenderTree.pro: + * QtTestBrowser/QtTestBrowser.pro: + * Scripts/webkitdirs.pm: + +2011-04-12 Tony Chang <tony@chromium.org> + + Reviewed by Andreas Kling. + + [Qt] embed checksums in PNGs written by Qt-DRT + https://bugs.webkit.org/show_bug.cgi?id=58173 + + * DumpRenderTree/qt/DumpRenderTreeQt.cpp: + (WebCore::DumpRenderTree::dump): + +2011-04-12 Eric Seidel <eric@webkit.org> + + Reviewed by Adam Barth. + + commit-queue should upload failure diffs when tests fail + https://bugs.webkit.org/show_bug.cgi?id=58348 + + This change was mostly just plumbing. We were already saving + this information for flaky test reporting. I just made it possible + for normal failures to report archives as well. + + I did a little abstraction work to try and share some code between + flakytestreporter.py and this new code. There is still more we could do. + + In making this change I also went through and updated the various + places we have urls hard-coded in our python and pointed them at + common.config.urls. + + * Scripts/webkitpy/common/checkout/scm.py: + * Scripts/webkitpy/common/net/bugzilla/bugzilla.py: + * Scripts/webkitpy/common/net/buildbot/buildbot.py: + * Scripts/webkitpy/common/net/statusserver.py: + * Scripts/webkitpy/layout_tests/port/base.py: + * Scripts/webkitpy/tool/bot/botinfo.py: Added. + * Scripts/webkitpy/tool/bot/botinfo_unittest.py: Added. + * Scripts/webkitpy/tool/bot/commitqueuetask.py: + * Scripts/webkitpy/tool/bot/flakytestreporter.py: + * Scripts/webkitpy/tool/bot/flakytestreporter_unittest.py: + * Scripts/webkitpy/tool/commands/queues.py: + +2011-04-12 Daniel Bates <dbates@rim.com> + + Rubber-stamped by Eric Seidel. + + svn-apply and/or patch(1) has trouble applying patches that makes changes to files + with Windows line endings + https://bugs.webkit.org/show_bug.cgi?id=53625 + + Fixes an issue where a patch made on a SCM checkout on a Unix file system cannot be + applied to an SCM checkout on a Windows file system and vice-versa. + + This issue manifests itself due to custom SCM settings as well as differences in + gitattributes support in older versions of Git (e.g. 1.7.0.3). We implement support + into svn-apply/unapply to compensate for differences in line endings by converting + the line endings in a patch to match the line endings in the target file (if it exists). + + * Scripts/VCSUtils.pm: + - Added parseFirstEOL(), which returns the first end-of-line character(s) that appear in the + content read from the specified file handle. Obviously, this heuristic will not work + for files with mixed line endings, but I don't envision such files to be the norm. If + this turns out to be an issue then we can improve the heuristic. + - Added firstEOLInFile(). + - Modified parsePatch() and parseDiff() to take an optional hash reference to an options hash. + In particular, added the hash key shouldNotUseIndexPathEOL to control whether to use the line + endings in the diff instead of the line endings in the target file. + - Extracted local variable $chunkRangeRegEx from fixChangeLogPatch() so that it can be + re-used in parseDiff(). + * Scripts/webkitperl/VCSUtils_unittest/parseDiff.pl: Modified to pass {shouldNotUseIndexPathEOL => 1} + to parsePatch() since these unit tests don't create mock files. Instead, created unit tests that use + mock files in file VCSUtils_unittest/parseDiffWithMockFiles.pl. + * Scripts/webkitperl/VCSUtils_unittest/parseDiffWithMockFiles.pl: Added. + * Scripts/webkitperl/VCSUtils_unittest/parseFirstEOL.pl: Added. + +2011-04-12 Sam Weinig <sam@webkit.org> + + Reviewed by Adam Roben. + + REGRESSION (r83550): Multiple http tests crashing in the web process in SQLite beneath CFNetwork on Windows 7 Release (WebKit2 Tests) + https://bugs.webkit.org/show_bug.cgi?id=58336 + + * WebKitTestRunner/TestController.cpp: + (WTR::TestController::resetStateToConsistentValues): + Remove cache clearing as that is causing tests to crash on Windows 7. + +2011-04-11 Sam Weinig <sam@webkit.org> + + Reviewed by Anders Carlsson. + + REGRESSION(r77974): http/tests/security/aboutBlank/security-context-window-open.html is failing + <rdar://problem/8981346> + https://bugs.webkit.org/show_bug.cgi?id=54159 + + * WebKitTestRunner/InjectedBundle/InjectedBundlePage.cpp: + (WTR::InjectedBundlePage::InjectedBundlePage): + (WTR::InjectedBundlePage::decidePolicyForNavigationAction): + (WTR::InjectedBundlePage::decidePolicyForNewWindowAction): + (WTR::InjectedBundlePage::decidePolicyForResponse): + (WTR::InjectedBundlePage::unableToImplementPolicy): + * WebKitTestRunner/InjectedBundle/InjectedBundlePage.h: + Add short-circuited policy client which matches WebKit1. + + * WebKitTestRunner/TestController.cpp: + (WTR::TestController::resetStateToConsistentValues): + Clear the cache between tests to ensure consistent results. + +2011-04-11 George Guo <George.Guo@nokia.com> + + Reviewed by Eric Seidel. + + prepare-ChangeLog support email input but -h did not show the option + https://bugs.webkit.org/show_bug.cgi?id=58164 + + Add email option to -h to improve the usability + + * Scripts/prepare-ChangeLog: + +2011-04-11 Dimitri Glazkov <dglazkov@chromium.org> + + Reviewed by Eric Carlson. + + Rename MediaControls to MediaControlRootElement. + https://bugs.webkit.org/show_bug.cgi?id=58250 + + * Scripts/do-webcore-rename: Documented the renaming. + +2011-04-11 Sam Weinig <sam@webkit.org> + + Fix Windows build. + + * MiniBrowser/win/BrowserView.cpp: + (BrowserView::create): + +2011-04-11 Sam Weinig <sam@webkit.org> + + Reviewed by Anders Carlsson. + + Move focus management out of WebKit via the UIClient + <rdar://problem/8784068> + https://bugs.webkit.org/show_bug.cgi?id=58278 + + * MiniBrowser/mac/BrowserWindowController.m: + (-[BrowserWindowController awakeFromNib]): + * WebKitTestRunner/TestController.cpp: + (WTR::TestController::createOtherPage): + (WTR::TestController::initialize): + Add stubs for new UIClient functions. + +2011-02-03 Martin Robinson <mrobinson@igalia.com> + + Reviewed by Eric Seidel. + + [GTK] The GTK+ DRT needs an implementation of the PlainTextController + https://bugs.webkit.org/show_bug.cgi?id=53605 + + Add an implementation of the PlainTextController for the GTK+ DRT. + + * DumpRenderTree/gtk/DumpRenderTree.cpp: + (addControllerToWindow): Added this helper method. + (webViewWindowObjectCleared): Use the new helper to add EventSender + and the PlainTextController to the window object. + * GNUmakefile.am: Added PlainTextController source files. + * DumpRenderTree/gtk/PlainTextController.cpp: Added. This will rely + on DumpRenderTreeSupportGtk to convert a JSValueRef into a WebKitDOMRange + until that functionality exists somewhere in the WebKitGTK+ stack. + * DumpRenderTree/gtk/PlainTextController.h: Added. + +2011-04-11 Yael Aharon <yael.aharon@nokia.com> + + Unreviewed. + + Adding my IRC nick. + + * Scripts/webkitpy/common/config/committers.py: + +2011-04-11 Dirk Pranke <dpranke@chromium.org> + + Reviewed by Adam Roben. + + new-run-webkit-tests: fix crash when running under windows cmd.exe + https://bugs.webkit.org/show_bug.cgi?id=58197 + + We would intermittently crash when running NRWT directly under + cmd.exe on windows because we were sharing the stdin file + descriptor between the python process and the http server. + cmd.exe really didn't like that, and there was no reason to + share the descriptor, so we now use a PIPE instead. + + * Scripts/webkitpy/layout_tests/port/http_server.py: + +2011-04-11 Dirk Pranke <dpranke@chromium.org> + + Reviewed by Ojan Vafai. + + new-run-webkit-tests: add unit tests for Port.diff_image() + https://bugs.webkit.org/show_bug.cgi?id=58196 + + Add the unit tests for the fix in bug 58195. + + * Scripts/webkitpy/layout_tests/port/chromium_unittest.py: + * Scripts/webkitpy/layout_tests/port/port_testcase.py: + * Scripts/webkitpy/layout_tests/port/webkit_unittest.py: + +2011-04-11 Dirk Pranke <dpranke@chromium.org> + + Reviewed by Tony Chang. + + new-run-webkit-tests: implement support for audio, take two + https://bugs.webkit.org/show_bug.cgi?id=58195 + + Attempt to re-land the fix for bug 58101 (which was initially + landed in r83330, but rolled out). This is the same patch but + fixes crashes in Port.diff_image() caused by the change for + empty image files being None instead of ''. + + * Scripts/webkitpy/layout_tests/layout_package/json_layout_results_generator.py: + * Scripts/webkitpy/layout_tests/layout_package/single_test_runner.py: + * Scripts/webkitpy/layout_tests/layout_package/test_expectations.py: + * Scripts/webkitpy/layout_tests/layout_package/test_failures.py: + * Scripts/webkitpy/layout_tests/layout_package/test_result_writer.py: + * Scripts/webkitpy/layout_tests/port/base.py: + * Scripts/webkitpy/layout_tests/port/chromium.py: + * Scripts/webkitpy/layout_tests/port/dryrun.py: + * Scripts/webkitpy/layout_tests/port/mock_drt.py: + * Scripts/webkitpy/layout_tests/port/mock_drt_unittest.py: + * Scripts/webkitpy/layout_tests/port/test.py: + * Scripts/webkitpy/layout_tests/port/webkit.py: + +2011-04-11 Mario Sanchez Prada <msanchez@igalia.com> + + Reviewed by Xan Lopez. + + [GTK] Implement AccessibilityUIElement::{row|column}IndexRange in DRT + https://bugs.webkit.org/show_bug.cgi?id=57854 + + Implement missing features in GTK's DRT. + + * DumpRenderTree/gtk/AccessibilityUIElementGtk.cpp: + (indexRangeInTable): New helper function to get the range string + for the current cell inside the parent table, either from the + point of view of rows or columns. + (AccessibilityUIElement::rowIndexRange): Implemented by relying on + the new helper function indexRangeInTable(). + (AccessibilityUIElement::columnIndexRange): Ditto. + +2011-04-11 Mario Sanchez Prada <msanchez@igalia.com> + + Reviewed by Chris Fleizach. + + [GTK] Implement AccessibilityUIElement::cellForColumnAndRow in DRT + https://bugs.webkit.org/show_bug.cgi?id=57826 + + Implement missing feature in GTK's DRT. + + * DumpRenderTree/gtk/AccessibilityUIElementGtk.cpp: + (AccessibilityUIElement::cellForColumnAndRow): Implemented, by + relying on the analogous function from the AtkTable interface. + +2011-04-05 Timothy Hatcher <timothy@apple.com> + + Fix the extract-localizable-strings script errors that started after + WEB_UI_STRING was added to LocalizedStrings.h in WebCore. + + * Scripts/extract-localizable-strings: Skip LocalizedStrings.h. + +2011-04-11 Tony Chang <tony@chromium.org> + + Reviewed by Eric Seidel. + + fix crc computation on 64 bit machines + https://bugs.webkit.org/show_bug.cgi?id=58243 + + unsigned long is dependenct on CPU architecture, so use unsigned which is always 32 bits + + * DumpRenderTree/CyclicRedundancyCheck.cpp: + (makeCrcTable): + (computeCrc): + * DumpRenderTree/CyclicRedundancyCheck.h: + * DumpRenderTree/PixelDumpSupport.cpp: + (appendIntToVector): + (convertChecksumToPNGComment): + +2011-04-10 Kimmo Kinnunen <kimmo.t.kinnunen@nokia.com> + + Reviewed by Eric Seidel. + + Require no undefined symbols during compilation. + + [Qt] [WK2] WebKitTestRunner, QtWebProcess and WTRInjectBundle should fail to compile when there's undefined symbols + https://bugs.webkit.org/show_bug.cgi?id=54896 + + Add -Wl,--no-undefined to catch missing symbols early. + + * WebKitTestRunner/InjectedBundle/qt/InjectedBundle.pro: + * WebKitTestRunner/qt/WebKitTestRunner.pro: + +2011-04-10 Kevin Ollivier <kevino@theolliviers.com> + + [wx] Unreviewed build fix. Remove collector dirs from the list of build dirs. + + * wx/build/settings.py: + +2011-04-10 Kevin Ollivier <kevino@theolliviers.com> + + [wx] Unreviewed build fix. Add Source/JavaScriptCore/heap to the list of directories. + + * wx/build/settings.py: + +2011-04-10 David Levin <levin@chromium.org> + + Reviewed by Dimitri Glazkov. + + REGRESSION(r83384): Change to chromium.py is resulting in failures of the test framework on linux. + https://bugs.webkit.org/show_bug.cgi?id=58201 + + * Scripts/webkitpy/layout_tests/port/chromium.py: Commented out the assert for now, + and filed bug 58202. + +2011-04-09 David Levin <levin@chromium.org> + + Unreviewed, rolling out r83394. + http://trac.webkit.org/changeset/83394 + https://bugs.webkit.org/show_bug.cgi?id=53625 + + Patch was incorrect as noted in the bug. + + * Scripts/svn-apply: + +2011-04-09 David Levin <levin@chromium.org> + + Reviewed by Adam Barth. + + svn-apply and/or patch(1) has trouble applying patches that makes changes to files with Windows line endings + https://bugs.webkit.org/show_bug.cgi?id=53625 + + * Scripts/svn-apply: Ensure that the portions of patches + which are for vcproj/vsprops files has DOS line endings. + +2011-04-09 Dirk Pranke <dpranke@chromium.org> + + Reviewed by Tony Chang. + + It looks like NRWT has not been stopping DRT/TestShell + instances properly on windows, probably for a long time. + This would go a long way to explaining why we often have + processes lying around :) + + https://bugs.webkit.org/show_bug.cgi?id=57807 + + * Scripts/webkitpy/layout_tests/port/chromium.py: + * Scripts/webkitpy/layout_tests/port/chromium_unittest.py: + +2011-04-09 Keith Kyzivat <keith.kyzivat@nokia.com> + + Reviewed by Laszlo Gombos. + + [Qt] Don't link against fontconfig or X11 if embedded + https://bugs.webkit.org/show_bug.cgi?id=58104 + + * DumpRenderTree/qt/DumpRenderTree.pro: fontconfig !included in embedded + * QtTestBrowser/QtTestBrowser.pro: ditto + * WebKitTestRunner/InjectedBundle/qt/InjectedBundle.pro: ditto + * WebKitTestRunner/qt/WebKitTestRunner.pro: ditto + +2011-04-08 Jon Honeycutt <jhoneycutt@apple.com> + + http/tests/loading/preload-append-scan.php is failing on Windows + https://bugs.webkit.org/show_bug.cgi?id=58178 + + Reviewed by Brian Weinstein. + + * DumpRenderTree/win/DumpRenderTree.cpp: + (lastPathComponent): + Use CFURL API to find the last path component, rather than + PathFindFileName(), because the latter will include the query string. + +2011-04-08 Jian Li <jianli@chromium.org> + + Unreviewed, rolling out r83327, r83330 since these patches are very + likely to break chromium webkit mac10.6 builders. + + * Scripts/webkitpy/layout_tests/layout_package/json_layout_results_generator.py: + * Scripts/webkitpy/layout_tests/layout_package/single_test_runner.py: + * Scripts/webkitpy/layout_tests/layout_package/test_expectations.py: + * Scripts/webkitpy/layout_tests/layout_package/test_failures.py: + * Scripts/webkitpy/layout_tests/layout_package/test_result_writer.py: + * Scripts/webkitpy/layout_tests/port/base.py: + * Scripts/webkitpy/layout_tests/port/chromium.py: + * Scripts/webkitpy/layout_tests/port/dryrun.py: + * Scripts/webkitpy/layout_tests/port/mock_drt.py: + * Scripts/webkitpy/layout_tests/port/mock_drt_unittest.py: + * Scripts/webkitpy/layout_tests/port/test.py: + * Scripts/webkitpy/layout_tests/port/webkit.py: + +2011-04-08 Vincent Scheib <scheib@chromium.org> + + Reviewed by Eric Seidel. + + add chromium-gpu-linux-x86_64 to the recognized list of ports + https://bugs.webkit.org/show_bug.cgi?id=58099 + + Add chromium-gpu-linux-x86_64 to fix assert. + + * Scripts/webkitpy/layout_tests/port/chromium_linux.py: + +2011-04-08 Alpha Lam <hclam@chromium.org> + + Unreviewed, rolling out r83335. + http://trac.webkit.org/changeset/83335 + https://bugs.webkit.org/show_bug.cgi?id=53556 + + GTK and QT bots are broken + + * Scripts/build-webkit: + +2011-04-07 Anna Cavender <annacc@chromium.org> + + Reviewed by Eric Carlson. + + Setup ENABLE(TRACK) feature define + https://bugs.webkit.org/show_bug.cgi?id=53556 + + * Scripts/build-webkit: + +2011-04-08 Dirk Pranke <dpranke@chromium.org> + + Reviewed by Adam Roben. + + new-run-webkit-tests: configure a NRWT test bot for Mac SL + https://bugs.webkit.org/show_bug.cgi?id=58114 + + This change removes the old new-run-webkit-tests entry and + updates it for a new test-only bot. + + * BuildSlaveSupport/build.webkit.org-config/config.json: + +2011-04-08 Dominic Cooney <dominicc@google.com> + + Reviewed by Adam Roben. + + Make layoutTestController.shadowRoot return null, not undefined, + when its argument is invalid. + https://bugs.webkit.org/show_bug.cgi?id=58121 + + * DumpRenderTree/mac/LayoutTestControllerMac.mm: + (LayoutTestController::shadowRoot): + * WebKitTestRunner/InjectedBundle/LayoutTestController.cpp: + (WTR::LayoutTestController::shadowRoot): + +2011-04-08 Pere Martir <pere.martir4@gmail.com> + + Reviewed by Adam Roben. + + Locate NSTD.EXE in 64-bit Windows + https://bugs.webkit.org/show_bug.cgi?id=57847 + + * Scripts/old-run-webkit-tests: + +2011-04-08 Adam Roben <aroben@apple.com> + + Qt build fix + + * DumpRenderTree/TestNetscapePlugIn/PluginObject.h: Pull in stdarg.h for va_list. + +2011-04-07 Adam Roben <aroben@apple.com> + + Test that NPP_SetWindow is passed a null window handle during plugin destruction on non-Mac platforms + + Test for <http://webkit.org/b/47009> WebKit2 needs to call NPP_SetWindow when destroying a + plugin + + Reviewed by Anders Carlsson. + + * DumpRenderTree/TestNetscapePlugIn/PluginObject.cpp: + (pluginLogWithArguments): Moved code to format and log the message here... + (pluginLog): ...from here. + + * DumpRenderTree/TestNetscapePlugIn/PluginObject.h: Added pluginLogWithArguments. + + * DumpRenderTree/TestNetscapePlugIn/PluginTest.cpp: + (PluginTest::log): Added. Calls through to pluginLogWithArguments. + + * DumpRenderTree/TestNetscapePlugIn/PluginTest.h: Added log. + + * DumpRenderTree/TestNetscapePlugIn/Tests/NPPSetWindowCalledDuringDestruction.cpp: Added. + (NPPSetWindowCalledDuringDestruction::setWillBeDestroyed): Records that destruction is about + to begin. + (NPPSetWindowCalledDuringDestruction::NPPSetWindowCalledDuringDestruction): Simple + constructor. + (NPPSetWindowCalledDuringDestruction::NPP_GetValue): Creates and returns a ScriptObject that + can be used to invoke our setWillBeDestroyed function. + (NPPSetWindowCalledDuringDestruction::NPP_SetWindow): Records what has happened (and logs if + anything unexpected happens). + (NPPSetWindowCalledDuringDestruction::NPP_Destroy): On Mac, logs a failure message if + NPP_SetWindow was called during destruction. On other platforms, logs a failure message if + NPP_SetWindow was *not* called during destruction. + (NPPSetWindowCalledDuringDestruction::ScriptObject::hasMethod): Return true for our only + method, setWillBeDestroyed. + (NPPSetWindowCalledDuringDestruction::ScriptObject::invoke): Call through to the PluginTest + object. + + * DumpRenderTree/DumpRenderTree.xcodeproj/project.pbxproj: + * DumpRenderTree/TestNetscapePlugIn/win/TestNetscapePlugin.vcproj: + * DumpRenderTree/qt/TestNetscapePlugin/TestNetscapePlugin.pro: + * GNUmakefile.am: + Added new test. + + * Scripts/old-run-webkit-tests: Skip the new test when using out-of-process plugins with + WebKit1 on Mac, since it can't work properly due to <http://webkit.org/b/58077>. + +2011-04-08 Mario Sanchez Prada <msanchez@igalia.com> + + Reviewed by Martin Robinson. + + [GTK] Implement increment() and decrement() functions in DRT's AccessibilityUIElement + https://bugs.webkit.org/show_bug.cgi?id=58039 + + Implement missing functions in GTK's DRT. + + * DumpRenderTree/gtk/AccessibilityUIElementGtk.cpp: + (AccessibilityUIElement::increment): Implemented. + (AccessibilityUIElement::decrement): Implemented. + +2011-04-08 Dominic Cooney <dominicc@google.com> + + Reviewed by Kent Tamura. + + Make WK2 layoutTestController.shadowRoot return undefined, not + null, when its argument is not an element. + https://bugs.webkit.org/show_bug.cgi?id=58121 + + * WebKitTestRunner/InjectedBundle/LayoutTestController.cpp: + (WTR::LayoutTestController::shadowRoot): + +2011-04-07 Dirk Pranke <dpranke@chromium.org> + + Reviewed by Mihai Parparita. + + Change reference port for Mac GPU baselines from + Leopard to SnowLeopard, XP to Win7, and Linux-x86 + to Linux x86-64. + + https://bugs.webkit.org/show_bug.cgi?id=58099 + + * Scripts/webkitpy/layout_tests/port/chromium.py: + +2011-04-07 Andrew Scherkus <scherkus@chromium.org> + + Revert ENABLE_TRACK patch due to compile failures. + + * Scripts/build-webkit: + +2011-04-07 Tony Chang <tony@chromium.org> + + Reviewed by Eric Seidel. + + update DRT to embed checksums in png files + https://bugs.webkit.org/show_bug.cgi?id=57871 + + We insert the bytes for the comment in printPNG rather than at encode + time because each platform does its own PNG encoding (either using CG + or cairo). Putting this in pringPNG avoids having to duplicate this + code, although it's not as clean as doing it at encoding time. + + We insert the comment right after the IHDR chunk of the PNG. + + * DumpRenderTree/DumpRenderTree.xcodeproj/project.pbxproj: + * DumpRenderTree/CyclicRedundancyCheck.cpp: Added. + (makeCrcTable): Ported from LayoutTests/fast/canvas/webgl/resources/pnglib.js + (computeCrc): Ported from LayoutTests/fast/canvas/webgl/resources/pnglib.js + * DumpRenderTree/CyclicRedundancyCheck.h: Added. + * DumpRenderTree/PixelDumpSupport.cpp: + (dumpWebViewAsPixelsAndCompareWithExpected): + (convertChecksumToPNGComment): Generate the bytes to insert. + (printPNG): Insert the png comment before the first IDAT section. + * DumpRenderTree/PixelDumpSupport.h: + * DumpRenderTree/cairo/PixelDumpSupportCairo.cpp: + (printPNG): + (dumpBitmap): + * DumpRenderTree/cg/PixelDumpSupportCG.cpp: + (printPNG): + (dumpBitmap): + * DumpRenderTree/win/DumpRenderTree.vcproj: + * GNUmakefile.am: + +2011-04-07 Jeff Miller <jeffm@apple.com> + + Reviewed by Adam Roben. + + Replace WKStringGetCharactersPtr() with WKStringGetCharacters() + https://bugs.webkit.org/show_bug.cgi?id=58058 + + * TestWebKitAPI/Tests/WebKit2/WKString.cpp: + (TestWebKitAPI::TEST): Add tests for WKStringGetLength() and WKStringGetCharactersPtr(). + +2011-04-07 Chang Shu <cshu@webkit.org> + + Reviewed by Darin Adler. + + WebKitTestRunner needs layoutTestController.isPageBoxVisible + https://bugs.webkit.org/show_bug.cgi?id=42695 + + * WebKitTestRunner/InjectedBundle/Bindings/LayoutTestController.idl: + * WebKitTestRunner/InjectedBundle/LayoutTestController.cpp: + (WTR::LayoutTestController::isPageBoxVisible): + * WebKitTestRunner/InjectedBundle/LayoutTestController.h: + +2011-04-07 Adam Roben <aroben@apple.com> + + Build fix + + * BuildSlaveSupport/build.webkit.org-config/master.cfg: Added a missing import. + +2011-04-07 Adam Roben <aroben@apple.com> + + Move ExtractTestResults[AndLeaks]'s summarizing code back from commandComplete() to finished() + + commandComplete() is never called for MasterShellCommands like ExtractTestResults[AndLeaks]. + (Unfortunately the buildbot documentation does not make this clear.) finished() is the only + hook we have, so we have to do our work there. I added a new addCustomURLs method which can + be overridden by subclasses to provide extra URLs before we call up to the base class (after + which adding more URLs is no longer possible). + + Really hopefully fixes <http://webkit.org/b/56032> Leaks viewer should be linked from leaks + bot results page + + Reviewed by John Sullivan. + + * BuildSlaveSupport/build.webkit.org-config/master.cfg: + (ExtractTestResults.addCustomURLs): Moved code to add the "view results" URL here... + (ExtractTestResults.finished): ...from here. This replaces commandComplete, since that + method is never called for MasterShellCommands. + (ExtractTestResultsAndLeaks.addCustomURLs): Replaced commandComplete (which is never called) + with this method (which is). + +2011-04-07 Adam Roben <aroben@apple.com> + + Move ExtractTestResults[AndLeaks]'s summarizing code from finished() to commandComplete() + + This matches how most of our other build steps work, so is good just for improving + consistency between build steps. It should also make it possible for + ExtractTestResultsAndLeaks to successfully add a URL to Leaks Viewer. (Previously we were + trying to do this in finished() after we had called up to the base class, but that was + apparently too late to add more URLs.) + + Hopefully fixes <http://webkit.org/b/56032> Leaks viewer should be linked from leaks bot + results page + + Reviewed by John Sullivan. + + * BuildSlaveSupport/build.webkit.org-config/master.cfg: + (ExtractTestResults): Added a descriptionDone property so that we don't have to manually + call setText to get the right text to show up for this step. This matches how most of our + other build steps work. + (ExtractTestResults.commandComplete): Replaced our override of finished with this function. + This is how most of our other build steps work. + (ExtractTestResultsAndLeaks.commandComplete): Replaced our override of finished with this + function, to match the base class. + +2011-04-07 Adam Barth <abarth@webkit.org> + + Reviewed by Maciej Stachowiak. + + webkit-patch shouldn't state the whole working copy when calling check-webkit-style + https://bugs.webkit.org/show_bug.cgi?id=58022 + + Previously, we were ignoring the args variable! This patch fixes the + regression introduced in http://trac.webkit.org/changeset/82771. + + * Scripts/webkitpy/tool/commands/download_unittest.py: + * Scripts/webkitpy/tool/mocktool.py: + * Scripts/webkitpy/tool/steps/checkstyle.py: + +2011-04-07 Maciej Stachowiak <mjs@apple.com> + + Reviewed by Adam Barth. + + REGRESSION: "webkit-patch land" doesn't work correctly in SVN subdirectories + https://bugs.webkit.org/show_bug.cgi?id=58017 + + * Scripts/webkitpy/common/checkout/scm.py: + * Scripts/webkitpy/common/checkout/scm_unittest.py: + +2011-04-06 Chang Shu <cshu@webkit.org> + + Reviewed by Darin Adler. + + WebKitTestRunner needs layoutTestController.pageSizeAndMarginsInPixels + https://bugs.webkit.org/show_bug.cgi?id=57984 + + * WebKitTestRunner/InjectedBundle/Bindings/LayoutTestController.idl: + * WebKitTestRunner/InjectedBundle/LayoutTestController.cpp: + (WTR::LayoutTestController::pageSizeAndMarginsInPixels): + * WebKitTestRunner/InjectedBundle/LayoutTestController.h: + +2011-04-06 Chris Rogers <crogers@google.com> + + Reviewed by Tony Chang. + + Add web audio support to DumpRenderTree (mac port) + https://bugs.webkit.org/show_bug.cgi?id=57969 + + * DumpRenderTree/LayoutTestController.cpp: + (LayoutTestController::LayoutTestController): + (setEncodedAudioDataCallback): + (LayoutTestController::staticFunctions): + * DumpRenderTree/LayoutTestController.h: + (LayoutTestController::dumpAsAudio): + (LayoutTestController::setDumpAsAudio): + (LayoutTestController::encodedAudioData): + (LayoutTestController::setEncodedAudioData): + * DumpRenderTree/mac/DumpRenderTree.mm: + (dumpAudio): + (dump): + +2011-04-06 Benjamin Poulain <benjamin.poulain@nokia.com> + + Reviewed by Kenneth Rohde Christiansen. + + [Qt] LayoutTestController needs to implement numberOfPendingGeolocationPermissionRequests + https://bugs.webkit.org/show_bug.cgi?id=56086 + + Add the missing method. + + * DumpRenderTree/qt/DumpRenderTreeQt.cpp: + (WebCore::DumpRenderTree::getAllPages): Add a method to return all the pages allocated for the current test. + * DumpRenderTree/qt/DumpRenderTreeQt.h: + * DumpRenderTree/qt/LayoutTestControllerQt.cpp: + (LayoutTestController::numberOfPendingGeolocationPermissionRequests): + +2011-04-06 Dai Mikurube <dmikurube@chromium.org> + + Reviewed by David Levin. + + Add QUOTA build flag for unified quota API + https://bugs.webkit.org/show_bug.cgi?id=57918 + + * Scripts/build-webkit: Added QUOTA build flag + +2011-04-06 Dirk Pranke <dpranke@chromium.org> + + Reviewed by Tony Chang. + + Adjust the apple webkit port's default timeout to match + old-run-webkit-tests at 35 seconds. + + https://bugs.webkit.org/show_bug.cgi?id=37738 + + * Scripts/webkitpy/layout_tests/port/mac.py: + +2011-04-06 Scott Cameron <sccameron@rim.com> + + Reviewed by Eric Seidel. + + Remove global variable $httpdPath and replace with the return value of + getHTTPDPath(). Also remove unnecessary calls to getHTTPDPath(). + https://bugs.webkit.org/show_bug.cgi?id=53499 + + * Scripts/run-iexploder-tests: + * Scripts/webkitperl/httpd.pm: + +2011-04-06 Kevin Ollivier <kevino@theolliviers.com> + + Reviewed by Darin Adler. + + Make sure JS_EXPORT_PRIVATE is an empty define when we aren't using the export macros. + + https://bugs.webkit.org/show_bug.cgi?id=27551 + + * DumpRenderTree/config.h: + * WebKitAPITest/config.h: + * WebKitTestRunner/config.h: + +2011-04-06 Tony Chang <tony@chromium.org> + + Reviewed by Darin Adler. + + teach run-webkit-tests to read checksums from png files + https://bugs.webkit.org/show_bug.cgi?id=57993 + + * Scripts/old-run-webkit-tests: Read the first 2k of a .png if there's + no .checksum and look for the checksum in there. + +2011-04-06 David Dorwin <ddorwin@chromium.org> + + Reviewed by David Levin. + + Enable fullscreen layout tests for Chromium + https://bugs.webkit.org/show_bug.cgi?id=55726 + + Make DumpRenderTree always run with fullscreen enabled (equivalent of --enable-fullscreen). + + * DumpRenderTree/chromium/WebPreferences.cpp: + (WebPreferences::applyTo): + +2011-04-06 Adam Roben <aroben@apple.com> + + Add a "view leaks" link to builds on SnowLeopard Intel Leaks + + Fixes <http://webkit.org/b/56032> Leaks viewer should be linked from leaks bot results page + + Reviewed by David Kilzer. + + * BuildSlaveSupport/build.webkit.org-config/master.cfg: + (ExtractTestResults.resultDirectoryURL): Added. Moved code to calculate the URL for the + build's results directory here... + (ExtractTestResults.finished): ...from here. + (ExtractTestResultsAndLeaks): New class that's used by the leaks builder + (ExtractTestResultsAndLeaks.finished): Calls up to the base class, but also adds a "view + leaks" link to point to Leaks Viewer for this build. + (TestFactory): Added ExtractTestResultsClass abstraction. This isn't overridden anywhere, + but it seemed good to add for consistency with BuildAndTestFactory. + (BuildAndTestFactory): Added ExtractTestResultsClass abstraction. + (BuildAndTestLeaksFactory): Use ExtractTestResultsAndLeaks as our ExtractTestResultsClass so + that we'll get a "view leaks" link. + +2011-04-06 Zan Dobersek <zandobersek@gmail.com> + + Reviewed by Eric Seidel. + + [Gtk] plugins/set-status.html fails + https://bugs.webkit.org/show_bug.cgi?id=57844 + + Allow an empty status text to be dumped. + + * DumpRenderTree/gtk/DumpRenderTree.cpp: + (webViewStatusBarTextChanged): + +2011-04-06 Chang Shu <cshu@webkit.org> + + Reviewed by Darin Adler. + + WebKitTestRunner needs layoutTestController.pageNumberForElementById + https://bugs.webkit.org/show_bug.cgi?id=42329 + + * WebKitTestRunner/InjectedBundle/Bindings/LayoutTestController.idl: + * WebKitTestRunner/InjectedBundle/LayoutTestController.cpp: + (WTR::LayoutTestController::pageNumberForElementById): + * WebKitTestRunner/InjectedBundle/LayoutTestController.h: + +2011-04-06 Sergio Villar Senin <svillar@igalia.com> + + Reviewed by Martin Robinson. + + [GTK] DumpRenderTree: do not try to free NULL SoupURIs + https://bugs.webkit.org/show_bug.cgi?id=57932 + + Some Layout tests have invalid URIs that do not generate valid + SoupURI instances. Do not try to free those NULL SoupURIs. + + * DumpRenderTree/gtk/DumpRenderTree.cpp: + (willSendRequestCallback): + +2011-04-06 Csaba Osztrogonác <ossy@webkit.org> + + Reviewed by Andreas Kling. + + ORWT shouldn't generate diff files for tests without expected files + https://bugs.webkit.org/show_bug.cgi?id=57846 + + * Scripts/old-run-webkit-tests: + +2011-04-05 Kevin Ollivier <kevino@theolliviers.com> + + [wx] Mac build fix. Handle cases where 10.4 SDK is not installed, and also add x86_64 arch + to deps. + + * wx/install-unix-extras: + +2011-04-05 Sheriff Bot <webkit.review.bot@gmail.com> + + Unreviewed, rolling out r82978, r82999, and r83001. + http://trac.webkit.org/changeset/82978 + http://trac.webkit.org/changeset/82999 + http://trac.webkit.org/changeset/83001 + https://bugs.webkit.org/show_bug.cgi?id=57913 + + Does not work in Python 2.5 (Requested by abarth on #webkit). + + * Scripts/webkitpy/common/system/executive.py: + * Scripts/webkitpy/common/system/executive_unittest.py: + +2011-04-05 Chang Shu <cshu@webkit.org> + + Reviewed by Darin Adler. + + WebKitTestRunner needs layoutTestController.numberOfPages + https://bugs.webkit.org/show_bug.cgi?id=42694 + + * WebKitTestRunner/InjectedBundle/Bindings/LayoutTestController.idl: + * WebKitTestRunner/InjectedBundle/LayoutTestController.cpp: + (WTR::LayoutTestController::numberOfPages): + * WebKitTestRunner/InjectedBundle/LayoutTestController.h: + +2011-04-05 Tony Chang <tony@chromium.org> + + Reviewed by Mihai Parparita. + + [chromium] stop putting results downloaded from WebKit Linux in chromium-linux-x86_64 + https://bugs.webkit.org/show_bug.cgi?id=57889 + + * Scripts/webkitpy/layout_tests/port/chromium.py: + * Scripts/webkitpy/layout_tests/port/test.py: + * Scripts/webkitpy/layout_tests/rebaseline_chromium_webkit_tests.py: + +2011-04-05 Adam Barth <abarth@webkit.org> + + Silly with statement, from the future! + + * Scripts/webkitpy/common/system/executive.py: + +2011-04-05 Adam Barth <abarth@webkit.org> + + Reviewed by Tony Chang. + + Don't use Exception.message because it's deprecated + https://bugs.webkit.org/show_bug.cgi?id=57892 + + Suppress the warning for now. When we move to Python 3, we might need + to something more dramatic. + + * Scripts/webkitpy/common/system/executive.py: + +2011-04-05 Mihai Parparita <mihaip@chromium.org> + + Reviewed by Ojan Vafai. + + Add builders.js to dashboard file list + https://bugs.webkit.org/show_bug.cgi?id=57899 + + Add file added by http://crrev.com/80538 to dashboard file list. + + * TestResultServer/handlers/dashboardhandler.py: + +2011-04-05 MORITA Hajime <morrita@google.com> + + Reviewed by Adam Barth. + + webkit-patch should print git's stderr when git svn dcommit fail + http://webkit.org/b/57861 + + * Scripts/webkitpy/common/checkout/scm.py: + +2011-04-05 Mihai Parparita <mihaip@chromium.org> + + Reviewed by Tony Chang. + + Add --baseline-search-path to NRWT + https://bugs.webkit.org/show_bug.cgi?id=56233 + + Add NRWT option to specify additional directories to look for baselines + (will be used by hardware GPU bots which will have local per-bot + expectations for some tests) + + * Scripts/webkitpy/common/system/filesystem_mock.py: + * Scripts/webkitpy/layout_tests/port/base.py: + * Scripts/webkitpy/layout_tests/port/base_unittest.py: + * Scripts/webkitpy/layout_tests/run_webkit_tests.py: + +2011-04-05 Adam Roben <aroben@apple.com> + + Strip off /results.html from results URLs before trying to load leaks files from them + + r82734 changed build.webkit.org's "view results" URLs to point straight to the results.html + files, rather than pointing to the directory that contains them. This is more convenient for + people browsing build.webkit.org, but confused Leaks Viewer. + + Fixes <http://webkit.org/b/57869> REGRESSION (r82734): Links in Leaks Viewer's Recent Builds + list don't work + + Reviewed by Joseph Pecoraro. + + * BuildSlaveSupport/build.webkit.org-config/public_html/LeaksViewer/RecentBuildsLoader.js: + (RecentBuildsLoader.prototype.start): Strip off "/results.html" from the results URL. + +2011-04-05 Carol Szabo <carol@webkit.org> + + Unreviewed. + + Updated my info in committers.py + + Scripts\webkitpy\common\config\committers.py + +2011-04-05 Csaba Osztrogonác <ossy@webkit.org> + + Reviewed by Laszlo Gombos. + + [Qt] Make WebKitLibraries optional for building QtWebKit + https://bugs.webkit.org/show_bug.cgi?id=57542 + + * Scripts/build-webkit: + +2011-04-05 Chang Shu <cshu@webkit.org> + + Reviewed by Laszlo Gombos. + + [Qt] MiniBrowser defaultUrl does not work + https://bugs.webkit.org/show_bug.cgi?id=57021 + + Match the behavior and coding of MiniBrowser to QtTestBrowser. + * MiniBrowser/qt/main.cpp: + (main): + +2011-04-05 Jade Han <jade.han@nokia.com> + + Reviewed by Laszlo Gombos. + + [Qt] [Symbian] Disable WebKitTestRunner for Symbian + https://bugs.webkit.org/show_bug.cgi?id=54977 + + This change is a preparation to enable building webkit2 for Symbian. + Bug 57834 is filed to fix and enable WebKitTestRunner for Symbian. + + * Tools.pro: + +2011-04-05 Zoltan Horvath <zoltan@webkit.org> + + Reviewed by Andreas Kling. + + [Qt] Fix timeoutTimer of MiniBrowser's UrlLoader + https://bugs.webkit.org/show_bug.cgi?id=57832 + + Only QWKPage has loadFinished signal so connect to it instead of BrowserWindow. + + * MiniBrowser/qt/UrlLoader.cpp: + (UrlLoader::UrlLoader): + +2011-04-05 Zoltan Horvath <zoltan@webkit.org> + + [Qt] Linux Release minimal build fix after r82919. + + * MiniBrowser/qt/BrowserWindow.cpp: + (BrowserWindow::loadURLListFromFile): + * QtTestBrowser/launcherwindow.cpp: + (LauncherWindow::loadURLListFromFile): + +2011-04-05 Zoltan Horvath <zoltan@webkit.org> + + Reviewed by Andreas Kling. + + [Qt] Make URL loader accessible from testbrowser's menus + https://bugs.webkit.org/show_bug.cgi?id=57823 + + Add "Load URLs from file" to QtTestBrowser's and to MiniBrowser's menu. + + * MiniBrowser/qt/BrowserWindow.cpp: + (BrowserWindow::BrowserWindow): + (BrowserWindow::loadURLListFromFile): + (BrowserWindow::~BrowserWindow): + * MiniBrowser/qt/BrowserWindow.h: + * QtTestBrowser/launcherwindow.cpp: + (LauncherWindow::LauncherWindow): + (LauncherWindow::~LauncherWindow): + (LauncherWindow::createChrome): + (LauncherWindow::loadURLListFromFile): + * QtTestBrowser/launcherwindow.h: + +2011-04-04 Sam Weinig <sam@webkit.org> + + Reviewed by Brian Weinstein. + + Remove duplicate API from WKContext + <rdar://problem/8727879> + https://bugs.webkit.org/show_bug.cgi?id=57815 + + * TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj: + * TestWebKitAPI/Tests/WebKit2/SendingMessagesToTheWebProcessBeforeItIsValid.cpp: Removed. + * TestWebKitAPI/win/TestWebKitAPI.vcproj: + Remove SendingMessagesToTheWebProcessBeforeItIsValid since the API it was testing is now removed. + +2011-04-04 Tony Chang <tony@chromium.org> + + Reviewed by Ojan Vafai. + + [chromium] don't write .checksum files if a fallback platform has an embedded checksum + https://bugs.webkit.org/show_bug.cgi?id=57783 + + * Scripts/webkitpy/layout_tests/rebaseline_chromium_webkit_tests.py: + * Scripts/webkitpy/layout_tests/rebaseline_chromium_webkit_tests_unittest.py: + +2011-04-04 Kevin Ollivier <kevino@theolliviers.com> + + [wx] Unreviewed build fix, run uninstall when cleaning to remove built files + from WebKitBuild. + + * Scripts/webkitdirs.pm: + +2011-04-04 Martin Robinson <mrobinson@igalia.com> + + Reviewed by Gustavo Noronha Silva. + + [GTK] WebGL support + https://bugs.webkit.org/show_bug.cgi?id=31517 + + Add support to the DRT for turning on WebGL when a layout tests requests it. + + * DumpRenderTree/gtk/LayoutTestControllerGtk.cpp: + (LayoutTestController::overridePreference): Allow turning on WebGL from tests. + +2011-04-04 Chang Shu <cshu@webkit.org> + + Reviewed by Darin Adler. + + WebKitTestRunner needs layoutTestController.setAllowFileAccessFromFileURLs + https://bugs.webkit.org/show_bug.cgi?id=57572 + + * WebKitTestRunner/InjectedBundle/Bindings/LayoutTestController.idl: + * WebKitTestRunner/InjectedBundle/LayoutTestController.cpp: + (WTR::LayoutTestController::setAllowFileAccessFromFileURLs): + * WebKitTestRunner/InjectedBundle/LayoutTestController.h: + +2011-04-04 Keith Kyzivat <keith.kyzivat@nokia.com> + + Reviewed by Csaba Osztrogonác. + + [Qt] DumpRenderTree breaks compilation in some uClibc environments + https://bugs.webkit.org/show_bug.cgi?id=57602 + + * DumpRenderTree/qt/main.cpp: + (get_backtrace): + +2011-04-04 Kevin Ollivier <kevino@theolliviers.com> + + [wx] Unreviewed build fix, add new LayoutTestController method stub to wx. + + * DumpRenderTree/wx/LayoutTestControllerWx.cpp: + (LayoutTestController::shadowRoot): + +2011-04-04 Pavel Podivilov <podivilov@chromium.org> + + Unreviewed, fix exception in rebaseline tool. + + * Scripts/webkitpy/layout_tests/rebaseline_chromium_webkit_tests.py: + +2011-04-02 Beth Dakin <bdakin@apple.com> + + Rubber-stamped by Geoff Garen. + + For Dan! + * DumpRenderTree/mac/DumpRenderTree.mm: + (resetWebViewToConsistentStateBeforeTesting): + +2011-04-02 Beth Dakin <bdakin@apple.com> + + Rubber-stamped by Geoff Garen. + + Need to reset the scale, much like zoom. + * DumpRenderTree/mac/DumpRenderTree.mm: + (resetWebViewToConsistentStateBeforeTesting): + +2011-04-02 Sam Weinig <sam@webkit.org> + + Reviewed by Beth Dakin. + + https://bugs.webkit.org/show_bug.cgi?id=57605 + Frame::pageScaleFactor() should not affect getBoundingClientRect() or + getClientRects() + -and corresponding- + <rdar://problem/9194541> + + Add DRT support for the scaleWebView SPI. + * DumpRenderTree/mac/EventSendingController.mm: + (+[EventSendingController isSelectorExcludedFromWebScript:]): + (+[EventSendingController webScriptNameForSelector:]): + (-[EventSendingController scalePageBy:atX:andY:]): + * WebKitTestRunner/InjectedBundle/Bindings/EventSendingController.idl: + * WebKitTestRunner/InjectedBundle/EventSendingController.cpp: + (WTR::EventSendingController::scalePageBy): + * WebKitTestRunner/InjectedBundle/EventSendingController.h: + * WebKitTestRunner/InjectedBundle/InjectedBundlePage.cpp: + (WTR::InjectedBundlePage::reset): + +2011-04-02 Dominic Cooney <dominicc@google.com> + + Reviewed by Martin Robinson. + + Add layoutTestController.shadowRoot to GTK DumpRenderTree. + https://bugs.webkit.org/show_bug.cgi?id=57551 + + * DumpRenderTree/gtk/LayoutTestControllerGtk.cpp: + (LayoutTestController::shadowRoot): + +2011-04-02 Patrick Gansterer <paroga@webkit.org> + + Reviewed by Eric Seidel. + + Remove AbstractStep._run_script and move script names to ports.py + https://bugs.webkit.org/show_bug.cgi?id=57704 + + Replace deprecated _run_script with _tool.executive.run_and_throw_if_fail. + + * Scripts/webkitpy/common/config/ports.py: + * Scripts/webkitpy/tool/commands/download_unittest.py: + * Scripts/webkitpy/tool/commands/roll_unittest.py: + * Scripts/webkitpy/tool/commands/upload_unittest.py: + * Scripts/webkitpy/tool/steps/abstractstep.py: + * Scripts/webkitpy/tool/steps/checkstyle.py: + * Scripts/webkitpy/tool/steps/preparechangelog.py: + * Scripts/webkitpy/tool/steps/preparechangelogfordepsroll.py: + * Scripts/webkitpy/tool/steps/preparechangelogforrevert.py: + +2011-04-02 Patrick Gansterer <paroga@webkit.org> + + Reviewed by Eric Seidel. + + Emulate shebang on Win32 + https://bugs.webkit.org/show_bug.cgi?id=55927 + + Scripts on Windows work only if they are called with the explicit interpreter. + Read the first line of scripts to detect the correct executable. + + * Scripts/webkitpy/common/config/ports.py: + * Scripts/webkitpy/common/system/executive.py: Added interpreter_for_script(). + * Scripts/webkitpy/common/system/executive_unittest.py: + +2011-04-01 Adam Barth <abarth@webkit.org> + + Reviewed by Eric Seidel. + + apos entities shouldn't show up in ChangeLogs when using webkit-patch + https://bugs.webkit.org/show_bug.cgi?id=57692 + + Previously, we were using BeautifulSoup to process XML from + bugs.webkit.org, but that's incorrect. We should be using + BeautifulStoneSoup to process the XML. We were getting the ' + entity wrong because ' is an XML entity but not an HTML entity. + + * Scripts/webkitpy/common/net/bugzilla/bugzilla.py: + * Scripts/webkitpy/common/net/bugzilla/bugzilla_unittest.py: + +2011-04-01 Sheriff Bot <webkit.review.bot@gmail.com> + + Unreviewed, rolling out r82721. + http://trac.webkit.org/changeset/82721 + https://bugs.webkit.org/show_bug.cgi?id=57687 + + This patch introduced assertion failures on the GTK+ bots. + (Requested by mrobinson on #webkit). + + * DumpRenderTree/gtk/LayoutTestControllerGtk.cpp: + (LayoutTestController::shadowRoot): + +2011-04-01 Csaba Osztrogonác <ossy@webkit.org> + + Unreviewed buildfix. + + [Qt][WK2] Build Webkit2 using "-2" option on Qt + https://bugs.webkit.org/show_bug.cgi?id=55074 + + * Scripts/build-webkit: Ensure that "-2" isn't passed to qmake. + (The isWK2() function removes it from @ARGV, but not from @options.) + +2011-04-01 Keith Kyzivat <keith.kyzivat@nokia.com> + + Reviewed by Csaba Osztrogonác. + + [Qt] [WK2] MiniBrowser.qrc not found - regression from rev 82671 + https://bugs.webkit.org/show_bug.cgi?id=57666 + + * MiniBrowser/qt/MiniBrowser.qrc: Renamed from Tools/MiniBrowser/MiniBrowser.qrc. + +2011-04-01 Dirk Pranke <dpranke@chromium.org> + + Reviewed by Adam Barth. + + new-run-webkit-tests: fix feature detection, skipped platform lists on mac + + We apparently never implemented the code to skip tests based on + what was compiled into DRT. Also, change the logic used to skip + platform directories to match what old-run-webkit-tests does: + skip every test not in a directory in the baseline search path. + + https://bugs.webkit.org/show_bug.cgi?id=57662 + + * Scripts/webkitpy/layout_tests/port/mac.py: + * Scripts/webkitpy/layout_tests/port/mac_unittest.py: + * Scripts/webkitpy/layout_tests/port/webkit.py: + +2011-03-29 Mark Rowe <mrowe@apple.com> + + Reviewed by Jon Honeycutt. + + <http://webkit.org/b/56730> new-run-webkit-tests fails on Lion seed + + Teach new-run-webkit-tests about the concept of an unreleased version of Mac OS X. + + * Scripts/webkitpy/layout_tests/port/chromium_mac.py: + * Scripts/webkitpy/layout_tests/port/chromium_mac_unittest.py: + * Scripts/webkitpy/layout_tests/port/mac.py: + * Scripts/webkitpy/layout_tests/port/mac_unittest.py: + +2011-04-01 Chang Shu <cshu@webkit.org> + + Reviewed by Csaba Osztrogonác. + + [Qt][WK2] Build Webkit2 using "-2" option on Qt + https://bugs.webkit.org/show_bug.cgi?id=55074 + + * Scripts/build-webkit: + +2011-04-01 Dirk Pranke <dpranke@chromium.org> + + Reviewed by Tony Chang. + + new-run-webkit-tests: remove spurious port version override in webkit.py + base.py provides a default implementation so this is just + breaking things. + + https://bugs.webkit.org/show_bug.cgi?id=57667 + + * Scripts/webkitpy/layout_tests/port/webkit.py: + * Scripts/webkitpy/layout_tests/port/mac_unittest.py: + +2011-04-01 Csaba Osztrogonác <ossy@webkit.org> + + Reviewed by Adam Roben. + + Make view results on waterfall direct link to results.html + https://bugs.webkit.org/show_bug.cgi?id=57671 + + * BuildSlaveSupport/build.webkit.org-config/master.cfg: Add "/results.html" to the URL. + * Scripts/old-run-webkit-tests: Add links to httpd access and error logs. + +2011-04-01 Sam Weinig <sam@webkit.org> + + Fix windows build. + + * TestWebKitAPI/Tests/WebKit2/win/HideFindIndicator.cpp: + (TestWebKitAPI::TEST): + * TestWebKitAPI/Tests/WebKit2/win/ResizeViewWhileHidden.cpp: + (TestWebKitAPI::flushMessages): + +2011-04-01 Sam Weinig <sam@webkit.org> + + Reviewed by Adam Roben. + + Add adoptWK to WKRetainPtr.h + https://bugs.webkit.org/show_bug.cgi?id=57670 + + * TestWebKitAPI/PlatformUtilities.h: + * TestWebKitAPI/Tests/WebKit2/AboutBlankLoad.cpp: + * TestWebKitAPI/Tests/WebKit2/CanHandleRequest.cpp: + * TestWebKitAPI/Tests/WebKit2/CanHandleRequest_Bundle.cpp: + * TestWebKitAPI/Tests/WebKit2/CookieManager.cpp: + * TestWebKitAPI/Tests/WebKit2/HitTestResultNodeHandle.cpp: + * TestWebKitAPI/Tests/WebKit2/PageLoadDidChangeLocationWithinPageForFrame.cpp: + * TestWebKitAPI/Tests/WebKit2/ResponsivenessTimerDoesntFireEarly.cpp: + * TestWebKitAPI/Tests/WebKit2/RestoreSessionStateContainingFormData.cpp: + (TestWebKitAPI::createSessionStateContainingFormData): + * WebKitTestRunner/StringFunctions.h: + Replace custom versions of adoptWK with the API on in WebKit2/WKRetainPtr.h. + +2011-04-01 Sam Weinig <sam@webkit.org> + + Reviewed by Adam Roben. + + Fix leak noticed by Adam Roben in LayoutTestController::shadowRoot. + + * WebKitTestRunner/InjectedBundle/LayoutTestController.cpp: + (WTR::LayoutTestController::shadowRoot): + Make judicious use of adoptWK(). + +2011-04-01 Sam Weinig <sam@webkit.org> + + Reviewed by Timothy Hatcher. + + Fix extract-localizable-strings for macro change from UI_STRING -> WEB_UI_STRING. + + * Scripts/extract-localizable-strings: + +2011-04-01 Anders Carlsson <andersca@apple.com> + + Reviewed by Sam Weinig. + + Shockwave plug-in doesn't accept mouse events + https://bugs.webkit.org/show_bug.cgi?id=57653 + <rdar://problem/8483273> + + Add a plug-in test. + + * DumpRenderTree/DumpRenderTree.xcodeproj/project.pbxproj: + * DumpRenderTree/TestNetscapePlugIn/PluginTest.cpp: + (PluginTest::indicateTestFailure): + Move code from NPDeallocateCalledBeforeNPShutdown::TestObject::~TestObject here. + + (PluginTest::NPN_ConvertPoint): + * DumpRenderTree/TestNetscapePlugIn/PluginTest.h: + * DumpRenderTree/TestNetscapePlugIn/Tests/NPDeallocateCalledBeforeNPShutdown.cpp: + (NPDeallocateCalledBeforeNPShutdown::TestObject::~TestObject): + Call indicateTestFailure. + + * DumpRenderTree/TestNetscapePlugIn/Tests/mac: Added. + * DumpRenderTree/TestNetscapePlugIn/Tests/mac/ConvertPoint.cpp: Added. + (ConvertPoint::ConvertPoint): + (ConvertPoint::testConvert): + (ConvertPoint::NPP_New): + +2011-04-01 Dominic Cooney <dominicc@google.com> + + Reviewed by Martin Robinson. + + Add layoutTestController.shadowRoot to GTK DumpRenderTree. + https://bugs.webkit.org/show_bug.cgi?id=57551 + + * DumpRenderTree/gtk/LayoutTestControllerGtk.cpp: + (LayoutTestController::shadowRoot): + +2011-04-01 Sam Weinig <sam@webkit.org> + + Reviewed by Anders Carlsson. + + WebKitTestRunner needs layoutTestController.shadowRoot + https://bugs.webkit.org/show_bug.cgi?id=57661 + + * WebKitTestRunner/InjectedBundle/Bindings/LayoutTestController.idl: + * WebKitTestRunner/InjectedBundle/LayoutTestController.cpp: + (WTR::LayoutTestController::shadowRoot): + * WebKitTestRunner/InjectedBundle/LayoutTestController.h: + Implement layoutTestController.shadowRoot for WebKit2. + +2011-04-01 Chang Shu <cshu@webkit.org> + + Reviewed by Darin Adler. + + WebKitTestRunner needs layoutTestController.setDatabaseQuota + https://bugs.webkit.org/show_bug.cgi?id=57568 + + * WebKitTestRunner/InjectedBundle/Bindings/LayoutTestController.idl: + * WebKitTestRunner/InjectedBundle/LayoutTestController.cpp: + (WTR::LayoutTestController::setDatabaseQuota): + * WebKitTestRunner/InjectedBundle/LayoutTestController.h: + +2011-04-01 Dirk Pranke <dpranke@chromium.org> + + Reviewed by Tony Chang. + + This patch completes the cleanup of + rebaseline-chromium-webkit-tests to work with all of the + variants of a platform (we can now rebaseline gpu- and non-gpu + files at the same time). + + When the rebaselining is complete, any lines declared as + REBASELINE in the expectations file that matches a test that was + actually rebaselined will be deleted, even if only one of the + variants was actually rebaselined. This may cause odd problems, + but is better than where we're at today. + + This change removes the -g flag and deprecates -w. The -g flag is gone + because GPU baselines are handled just like any other variant. + The -w flag is deprecated because this tool now only works + against the canaries, since that's the only place we have a full + set of bots. It will be trivial to change this to + build.webkit.org if we decide that's where we want them to be. + + Also, this patch deletes a lot of cruft that is no longer needed + in the test_expectations code and the port-specific code. + + https://bugs.webkit.org/show_bug.cgi?id=55191 + + * Scripts/webkitpy/layout_tests/layout_package/test_expectations.py: + * Scripts/webkitpy/layout_tests/layout_package/test_expectations_unittest.py: + * Scripts/webkitpy/layout_tests/port/base.py: + * Scripts/webkitpy/layout_tests/port/base_unittest.py: + * Scripts/webkitpy/layout_tests/port/chromium.py: + * Scripts/webkitpy/layout_tests/port/chromium_gpu.py: + * Scripts/webkitpy/layout_tests/port/chromium_linux.py: + * Scripts/webkitpy/layout_tests/port/chromium_mac.py: + * Scripts/webkitpy/layout_tests/port/chromium_mac_unittest.py: + * Scripts/webkitpy/layout_tests/port/chromium_win.py: + * Scripts/webkitpy/layout_tests/port/chromium_win_unittest.py: + * Scripts/webkitpy/layout_tests/port/mac.py: + * Scripts/webkitpy/layout_tests/port/test.py: + * Scripts/webkitpy/layout_tests/port/webkit.py: + * Scripts/webkitpy/layout_tests/port/win.py: + * Scripts/webkitpy/layout_tests/rebaseline_chromium_webkit_tests.py: + * Scripts/webkitpy/layout_tests/rebaseline_chromium_webkit_tests_unittest.py: + +2011-04-01 Dirk Pranke <dpranke@chromium.org> + + Reviewed by Adam Barth. + + rebaseline-chromium-webkit-tests does not work correctly with + version-specific baselines. This patch updates the tool to use + all of the version-specific bots on the canaries, and will now + attempt to rebaseline all of the versions by default, although + it will not update both GPU and CPU versions. + + Also, it will no longer modify the test_expectations.txt file + *at all*. You will have to manually delete the REBASELINE lines + after running the tool and determining that it did what you + wanted it to do. This should be fixed in a separate bug - see + webkit bug #55191. + + https://bugs.webkit.org/show_bug.cgi?id=55608 + + * Scripts/webkitpy/layout_tests/layout_package/test_expectations.py: + * Scripts/webkitpy/layout_tests/layout_package/test_expectations_unittest.py: + * Scripts/webkitpy/layout_tests/port/chromium.py: + * Scripts/webkitpy/layout_tests/port/test.py: + * Scripts/webkitpy/layout_tests/rebaseline_chromium_webkit_tests.py: + * Scripts/webkitpy/layout_tests/rebaseline_chromium_webkit_tests_unittest.py: + +2011-03-31 Tony Chang <tony@chromium.org> + + Reviewed by Ojan Vafai. + + [chromium] update the rebaseline tool to know about pngs with checksums + https://bugs.webkit.org/show_bug.cgi?id=57481 + + * Scripts/webkitpy/layout_tests/rebaseline_chromium_webkit_tests.py: Skip over .checksum files if the checksum is already in the png + * Scripts/webkitpy/layout_tests/rebaseline_chromium_webkit_tests_unittest.py: + +2011-04-01 Adam Roben <aroben@apple.com> + + Retrieve revision numbers from the build's got_revision property in Leaks Viewer + + Previously, we were getting the revision of the first revision that triggered a build. + Choosing the last revision would have been more accurate. But got_revision is what is used + everywhere else on build.webkit.org, and should work even when there were no changes that + triggered a build (e.g., if someone clicked the Force Build button). + + Fixes <http://webkit.org/b/57630> Leaks viewer gets some revision numbers wrong in the + recent builds list + + Reviewed by Anders Carlsson. + + * BuildSlaveSupport/build.webkit.org-config/public_html/LeaksViewer/RecentBuildsLoader.js: + (RecentBuildsLoader.prototype.start): Pull the revision number out of the got_revision + property, rather than out of the first (i.e., earliest) change in the sourceStamp object. + + * BuildSlaveSupport/build.webkit.org-config/public_html/LeaksViewer/Utilities.js: + (Array.prototype.first): Added this helper function to return the first element in an array + that matches the given predicate, or null if no such element exists. + +2011-03-31 Adam Roben <aroben@apple.com> + + Prefer (but don't require) bug URLs to be on their own line when parsing bug numbers from ChangeLogs + + Fixes <http://webkit.org/b/57579> webkit-patch is too strict about bug URL formatting + + Reviewed by Darin Adler. + + * Scripts/webkitpy/common/net/bugzilla/bugzilla.py: + (parse_bug_id_from_changelog): Fall back to parse_bug_id if we weren't able to find a bug + URL on its own line. + + * Scripts/webkitpy/common/net/bugzilla/bugzilla_unittest.py: + (BugzillaTest.test_parse_bug_id_from_changelog): Updated expected results for test + progression, and added a new test that uses a short bug URL while I was at it. + +2011-04-01 Adam Roben <aroben@apple.com> + + Mark .vcproj/.vsprops/.sln files as being Windows-only + + Fixes <http://webkit.org/b/57489> Mac builders built 82512, but shouldn't have + + Reviewed by Anders Carlsson. + + * Scripts/webkitpy/common/config/build.py: + (_should_file_trigger_build): Added patterns to mark .vcproj/.vsprops/.sln files and .vcproj + directories as Windows-only. + + * Scripts/webkitpy/common/config/build_unittest.py: + (ShoulBuildTest): Added test cases for the above. + +2011-04-01 Keith Kyzivat <keith.kyzivat@nokia.com> + + Reviewed by Laszlo Gombos. + + [Qt] Build MiniBrowser for Symbian + https://bugs.webkit.org/show_bug.cgi?id=56319 + + Have MiniBrowser reference it's own copy of useragentlist.txt instead + of copying QtTestBrowser's. + Remove Tools/MiniBrowser/DerivedSources.pro + This reduces complexity in the Tools scripts due to Symbian limitations. + + * DerivedSources.pro: + * MiniBrowser/DerivedSources.pro: Removed. + * MiniBrowser/MiniBrowser.qrc: + * MiniBrowser/qt/MiniBrowser.pro: + * Scripts/webkitdirs.pm: + +2011-03-31 Chang Shu <cshu@webkit.org> + + Reviewed by Darin Adler. + + WebKitTestRunner needs layoutTestController.clearAllDatabases + https://bugs.webkit.org/show_bug.cgi?id=42540 + + * WebKitTestRunner/InjectedBundle/Bindings/LayoutTestController.idl: + * WebKitTestRunner/InjectedBundle/InjectedBundle.cpp: + (WTR::InjectedBundle::beginTesting): + * WebKitTestRunner/InjectedBundle/LayoutTestController.cpp: + (WTR::LayoutTestController::clearAllDatabases): + * WebKitTestRunner/InjectedBundle/LayoutTestController.h: + +2011-03-31 Chang Shu <cshu@webkit.org> + + Reviewed by Darin Adler. + + WebKitTestRunner needs layoutTestController.setAllowUniversalAccessFromFileURLs + https://bugs.webkit.org/show_bug.cgi?id=42692 + + * WebKitTestRunner/InjectedBundle/Bindings/LayoutTestController.idl: + +2011-03-31 Darin Adler <darin@apple.com> + + Reviewed by Sam Weinig. + + Implement mouseDown, mouseUp, and mouseMoveTo in WebKitTestRunner + https://bugs.webkit.org/show_bug.cgi?id=57573 + + * WebKitTestRunner/InjectedBundle/Bindings/EventSendingController.idl: + Added real definitions for mouseDown, mouseUp, mouseMoveTo and leapForward. + Removed fake definitions of keyDown and contextClick. + + * WebKitTestRunner/InjectedBundle/EventSendingController.cpp: + (WTR::operator==): Added. So we can compare two WKPoint structs. + (WTR::parseModifier): Added. + (WTR::parseModifierArray): Added. + (WTR::EventSendingController::EventSendingController): Initialize the + new data members. + (WTR::EventSendingController::mouseDown): Added. Calls + WKBundlePageSimulateMouseDown. + (WTR::EventSendingController::mouseUp): Added. Calls + WKBundlePageSimulateMouseUp. + (WTR::EventSendingController::mouseMoveTo): Added. Calls + WKBundlePageSimulateMouseMotion. + (WTR::EventSendingController::leapForward): Added. + (WTR::EventSendingController::updateClickCount): Added. Used by the + mouseDown/Up functions to create a click count. + + * WebKitTestRunner/InjectedBundle/EventSendingController.h: Updated + for the changes above. + +2011-03-31 Sergio Villar Senin <svillar@igalia.com> + + Reviewed by Martin Robinson. + + [GTK] implement LayoutTestController::setWillSendRequestReturnsNull + https://bugs.webkit.org/show_bug.cgi?id=57362 + + Do not generate DRT output if willSendRequestReturnsNull is set. + + * DumpRenderTree/gtk/DumpRenderTree.cpp: + (willSendRequestCallback): + +2011-03-31 Vamshikrishna.Yellenki <vamshi@motorola.com> and Alejandro G. Castro <alex@igalia.com> + + Reviewed by Martin Robinson. + + Implement MiniBrowser for Gtk port. + https://bugs.webkit.org/show_bug.cgi?id=48512 + + Initial implementation of the Gtk MiniBrowser. + + * MiniBrowser/gtk/GNUmakefile.am: Added. + * MiniBrowser/gtk/main.c: Added. + (activateUriEntryCallback): + (destroyCallback): + (goBackCallback): + (goForwardCallback): + (createToolbar): + (createWebView): + (createWindow): + (argumentToURL): + (main): + +2011-03-30 Dominic Cooney <dominicc@google.com> + + Reviewed by Dimitri Glazkov. + + Adds layoutTestController.shadowRoot accessor to Mac DRT. + https://bugs.webkit.org/show_bug.cgi?id=57415 + + * DumpRenderTree/LayoutTestController.cpp: + (shadowRootCallback): + (LayoutTestController::staticFunctions): + * DumpRenderTree/LayoutTestController.h: + * DumpRenderTree/mac/LayoutTestControllerMac.mm: + (LayoutTestController::shadowRoot): + * DumpRenderTree/win/LayoutTestControllerWin.cpp: + (LayoutTestController::shadowRoot): + +2011-03-30 Matthew Delaney <mdelaney@apple.com> + + Reviewed by Chris Marrin. + + Update fast/canvas tests to avoid dumping the render tree when possible + https://bugs.webkit.org/show_bug.cgi?id=57493 + + * DumpRenderTree/mac/DumpRenderTree.mm: Make DRT aware of new default values for + accelerated drawing and accelerated drawing for canvas + +2011-03-30 Adam Roben <aroben@apple.com> + + Stop ignoring leaks in CGGradientCreateWithColorStops + + Fixes <rdar://problem/7888547>. + + Rubber-stamped by John Sullivan. + + * Scripts/old-run-webkit-tests: + (countAndPrintLeaks): Removed some code to ignore those leaks. + +2011-03-30 Timur Iskhodzhanov <timurrrr@google.com> + + Reviewed by Alexey Proskuryakov. + + Add some dynamic annotations to JavaScriptCore/wtf + https://bugs.webkit.org/show_bug.cgi?id=53747 + + By using these annotations we can improve the precision of finding + WebKit errors using dynamic analysis tools like ThreadSanitizer and Valgrind. + These annotations don't affect the compiled binaries unless USE(DYNAMIC_ANNOTATIONS) is "1". + + These files don't add new functionality, so don't need extra tests. + + * DumpRenderTree/ForwardingHeaders/wtf/DynamicAnnotations.h: Added. + +2011-03-30 Steve Falkenburg <sfalken@apple.com> + + Reviewed by Adam Roben. + + Share most vsprops between Release and Production builds in releaseproduction.vsprops + https://bugs.webkit.org/show_bug.cgi?id=57508 + + * DumpRenderTree/TestNetscapePlugIn/win/TestNetscapePluginProduction.vsprops: + * DumpRenderTree/TestNetscapePlugIn/win/TestNetscapePluginRelease.vsprops: + * DumpRenderTree/TestNetscapePlugIn/win/TestNetscapePluginReleaseCairoCFLite.vsprops: + * DumpRenderTree/win/DumpRenderTreeProduction.vsprops: + * DumpRenderTree/win/DumpRenderTreeRelease.vsprops: + * DumpRenderTree/win/DumpRenderTreeReleaseCairoCFLite.vsprops: + * DumpRenderTree/win/ImageDiffProduction.vsprops: + * DumpRenderTree/win/ImageDiffRelease.vsprops: + * DumpRenderTree/win/ImageDiffReleaseCairoCFLite.vsprops: + * FindSafari/FindSafariProduction.vsprops: + * FindSafari/FindSafariRelease.vsprops: + * FindSafari/FindSafariReleaseCairoCFLite.vsprops: + * FindSafari/FindSafariReleasePGO.vsprops: + * MiniBrowser/Configurations/MiniBrowserProduction.vsprops: + * MiniBrowser/Configurations/MiniBrowserRelease.vsprops: + * MiniBrowser/Configurations/MiniBrowserReleaseCairoCFLite.vsprops: + * TestWebKitAPI/Configurations/TestWebKitAPIRelease.vsprops: + * TestWebKitAPI/Configurations/TestWebKitAPIReleaseCairoCFLite.vsprops: + * WebKitAPITest/WebKitAPITestProduction.vsprops: + * WebKitAPITest/WebKitAPITestRelease.vsprops: + * WebKitAPITest/WebKitAPITestReleaseCairoCFLite.vsprops: + * WebKitLauncherWin/WebKitLauncherWinProduction.vsprops: + * WebKitLauncherWin/WebKitLauncherWinRelease.vsprops: + * WebKitLauncherWin/WebKitLauncherWinReleaseCairoCFLite.vsprops: + * WebKitTestRunner/win/InjectedBundleProduction.vsprops: + * WebKitTestRunner/win/InjectedBundleRelease.vsprops: + * WebKitTestRunner/win/InjectedBundleReleaseCairoCFLite.vsprops: + * WebKitTestRunner/win/WebKitTestRunnerProduction.vsprops: + * WebKitTestRunner/win/WebKitTestRunnerRelease.vsprops: + * WebKitTestRunner/win/WebKitTestRunnerReleaseCairoCFLite.vsprops: + * WinLauncher/WinLauncherProduction.vsprops: + * WinLauncher/WinLauncherRelease.vsprops: + * WinLauncher/WinLauncherReleaseCairoCFLite.vsprops: + * record-memory-win/record-memory-winProduction.vsprops: + * record-memory-win/record-memory-winRelease.vsprops: + * record-memory-win/record-memory-winReleaseCairoCFLite.vsprops: + 2011-03-30 Steve Falkenburg <sfalken@apple.com> Reviewed by Adam Roben. diff --git a/Tools/DerivedSources.pro b/Tools/DerivedSources.pro index 55a26a2..802f3f7 100644 --- a/Tools/DerivedSources.pro +++ b/Tools/DerivedSources.pro @@ -2,7 +2,6 @@ TEMPLATE = subdirs CONFIG += ordered SUBDIRS += \ - MiniBrowser/DerivedSources.pro \ WebKitTestRunner/DerivedSources.pro for(subpro, SUBDIRS) { diff --git a/Tools/DumpRenderTree/CyclicRedundancyCheck.cpp b/Tools/DumpRenderTree/CyclicRedundancyCheck.cpp new file mode 100644 index 0000000..361ea0f --- /dev/null +++ b/Tools/DumpRenderTree/CyclicRedundancyCheck.cpp @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2010, Robert Eisele <robert@xarg.org> All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * 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. + * * Neither the name of Google Inc. 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 THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT + * OWNER OR 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. + */ + +#include "config.h" +#include "CyclicRedundancyCheck.h" + +#include <wtf/Vector.h> + +static void makeCrcTable(unsigned crcTable[256]) +{ + for (unsigned i = 0; i < 256; i++) { + unsigned c = i; + for (int k = 0; k < 8; k++) { + if (c & 1) + c = -306674912 ^ ((c >> 1) & 0x7fffffff); + else + c = c >> 1; + } + crcTable[i] = c; + } +} + +unsigned computeCrc(const Vector<unsigned char>& buffer) +{ + static unsigned crcTable[256]; + static bool crcTableComputed = false; + if (!crcTableComputed) { + makeCrcTable(crcTable); + crcTableComputed = true; + } + + unsigned crc = 0xffffffffL; + for (size_t i = 0; i < buffer.size(); ++i) + crc = crcTable[(crc ^ buffer[i]) & 0xff] ^ ((crc >> 8) & 0x00ffffffL); + return crc ^ 0xffffffffL; +} + diff --git a/Tools/DumpRenderTree/CyclicRedundancyCheck.h b/Tools/DumpRenderTree/CyclicRedundancyCheck.h new file mode 100644 index 0000000..ef1d78e --- /dev/null +++ b/Tools/DumpRenderTree/CyclicRedundancyCheck.h @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2011 Google 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: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * 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. + * * Neither the name of Google Inc. 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 THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT + * OWNER OR 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. + */ + +#ifndef CyclicRedundancyCheck_h +#define CyclicRedundancyCheck_h + +#include <wtf/Vector.h> + +unsigned computeCrc(const Vector<unsigned char>&); + +#endif diff --git a/Tools/DumpRenderTree/DumpRenderTree.xcodeproj/project.pbxproj b/Tools/DumpRenderTree/DumpRenderTree.xcodeproj/project.pbxproj index 67a7556..4eaecb9 100644 --- a/Tools/DumpRenderTree/DumpRenderTree.xcodeproj/project.pbxproj +++ b/Tools/DumpRenderTree/DumpRenderTree.xcodeproj/project.pbxproj @@ -36,6 +36,7 @@ 1A215A8211F2609C008AD0F5 /* PluginTest.h in Headers */ = {isa = PBXBuildFile; fileRef = 1A215A8011F2609C008AD0F5 /* PluginTest.h */; }; 1A215BE711F27658008AD0F5 /* DocumentOpenInDestroyStream.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A215A7511F26072008AD0F5 /* DocumentOpenInDestroyStream.cpp */; }; 1A24BAA9120734EE00FBB059 /* NPRuntimeObjectFromDestroyedPlugin.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A24BAA8120734EE00FBB059 /* NPRuntimeObjectFromDestroyedPlugin.cpp */; }; + 1A31EB3813466AC100017372 /* ConvertPoint.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A31EB3713466AC100017372 /* ConvertPoint.cpp */; }; 1A3E28AA1311D73B00501349 /* GetURLWithJavaScriptURLDestroyingPlugin.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A3E28A91311D73B00501349 /* GetURLWithJavaScriptURLDestroyingPlugin.cpp */; }; 1A8F02E80BB9B4EC008CFA34 /* TestObject.h in Headers */ = {isa = PBXBuildFile; fileRef = 1A8F024C0BB9B056008CFA34 /* TestObject.h */; }; 1AC6C8490D07638600CD3161 /* main.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1AC6C77F0D07589B00CD3161 /* main.cpp */; }; @@ -58,6 +59,8 @@ 4437730F125CBC4D00AAE02C /* WebArchiveDumpSupport.h in Headers */ = {isa = PBXBuildFile; fileRef = 44A997820FCDE86400580F10 /* WebArchiveDumpSupport.h */; }; 5185F6B210714E07007AA393 /* HistoryDelegate.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5185F69F10714A57007AA393 /* HistoryDelegate.mm */; }; 5185F6B310714E12007AA393 /* HistoryDelegate.h in Headers */ = {isa = PBXBuildFile; fileRef = 5185F69E10714A57007AA393 /* HistoryDelegate.h */; }; + 53CBB832134E42F3001CE6A4 /* CyclicRedundancyCheck.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 53CBB830134E42F3001CE6A4 /* CyclicRedundancyCheck.cpp */; }; + 53CBB833134E42F3001CE6A4 /* CyclicRedundancyCheck.h in Headers */ = {isa = PBXBuildFile; fileRef = 53CBB831134E42F3001CE6A4 /* CyclicRedundancyCheck.h */; }; 5DB9AC970F722C3600684641 /* AHEM____.TTF in Copy Font Files */ = {isa = PBXBuildFile; fileRef = AA7F10C20CB3C1030003BDC9 /* AHEM____.TTF */; }; 5DB9AC980F722C3600684641 /* WebKitWeightWatcher100.ttf in Copy Font Files */ = {isa = PBXBuildFile; fileRef = 375F09710DAC3CB600C8B4E5 /* WebKitWeightWatcher100.ttf */; }; 5DB9AC990F722C3600684641 /* WebKitWeightWatcher200.ttf in Copy Font Files */ = {isa = PBXBuildFile; fileRef = 375F09720DAC3CB600C8B4E5 /* WebKitWeightWatcher200.ttf */; }; @@ -136,6 +139,7 @@ BCD08B3A0E1057EF00A7D0C1 /* AccessibilityController.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BCD08B390E1057EF00A7D0C1 /* AccessibilityController.cpp */; }; BCD08B710E1059D200A7D0C1 /* AccessibilityControllerMac.mm in Sources */ = {isa = PBXBuildFile; fileRef = BCD08B700E1059D200A7D0C1 /* AccessibilityControllerMac.mm */; }; BCF6C6500C98E9C000AC063E /* GCController.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BCF6C64F0C98E9C000AC063E /* GCController.cpp */; }; + C031182B134E4A2B00919757 /* NPPSetWindowCalledDuringDestruction.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C031182A134E4A2B00919757 /* NPPSetWindowCalledDuringDestruction.cpp */; }; C06F9ABC1267A7060058E1F6 /* PassDifferentNPPStruct.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C06F9ABB1267A7060058E1F6 /* PassDifferentNPPStruct.cpp */; }; C0E720751281C828004EF533 /* EvaluateJSAfterRemovingPluginElement.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C0E720741281C828004EF533 /* EvaluateJSAfterRemovingPluginElement.cpp */; }; C0EC3C9C12787F0500939164 /* NullNPPGetValuePointer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C0EC3C9B12787F0500939164 /* NullNPPGetValuePointer.cpp */; }; @@ -209,6 +213,7 @@ 1A215A7F11F2609C008AD0F5 /* PluginTest.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = PluginTest.cpp; sourceTree = "<group>"; }; 1A215A8011F2609C008AD0F5 /* PluginTest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PluginTest.h; sourceTree = "<group>"; }; 1A24BAA8120734EE00FBB059 /* NPRuntimeObjectFromDestroyedPlugin.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = NPRuntimeObjectFromDestroyedPlugin.cpp; sourceTree = "<group>"; }; + 1A31EB3713466AC100017372 /* ConvertPoint.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ConvertPoint.cpp; sourceTree = "<group>"; }; 1A3E28A91311D73B00501349 /* GetURLWithJavaScriptURLDestroyingPlugin.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = GetURLWithJavaScriptURLDestroyingPlugin.cpp; sourceTree = "<group>"; }; 1A8F024C0BB9B056008CFA34 /* TestObject.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TestObject.h; sourceTree = "<group>"; }; 1AC6C77F0D07589B00CD3161 /* main.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = main.cpp; sourceTree = "<group>"; }; @@ -241,6 +246,8 @@ 44A997830FCDE86400580F10 /* WebArchiveDumpSupport.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = WebArchiveDumpSupport.cpp; path = cf/WebArchiveDumpSupport.cpp; sourceTree = "<group>"; }; 5185F69E10714A57007AA393 /* HistoryDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = HistoryDelegate.h; path = mac/HistoryDelegate.h; sourceTree = "<group>"; }; 5185F69F10714A57007AA393 /* HistoryDelegate.mm */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.objcpp; fileEncoding = 4; name = HistoryDelegate.mm; path = mac/HistoryDelegate.mm; sourceTree = "<group>"; }; + 53CBB830134E42F3001CE6A4 /* CyclicRedundancyCheck.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CyclicRedundancyCheck.cpp; sourceTree = "<group>"; }; + 53CBB831134E42F3001CE6A4 /* CyclicRedundancyCheck.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CyclicRedundancyCheck.h; sourceTree = "<group>"; }; 8465E2C60FFA8DF2003B8342 /* PixelDumpSupport.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = PixelDumpSupport.cpp; sourceTree = "<group>"; }; 9335435F03D75502008635CE /* WebKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = WebKit.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 933BF5A90F93FA5C000F0441 /* PlainTextController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = PlainTextController.h; path = mac/PlainTextController.h; sourceTree = "<group>"; }; @@ -317,6 +324,7 @@ BCD08B390E1057EF00A7D0C1 /* AccessibilityController.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = AccessibilityController.cpp; sourceTree = "<group>"; }; BCD08B700E1059D200A7D0C1 /* AccessibilityControllerMac.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = AccessibilityControllerMac.mm; path = mac/AccessibilityControllerMac.mm; sourceTree = "<group>"; }; BCF6C64F0C98E9C000AC063E /* GCController.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = GCController.cpp; sourceTree = "<group>"; }; + C031182A134E4A2B00919757 /* NPPSetWindowCalledDuringDestruction.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = NPPSetWindowCalledDuringDestruction.cpp; sourceTree = "<group>"; }; C06F9ABB1267A7060058E1F6 /* PassDifferentNPPStruct.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = PassDifferentNPPStruct.cpp; sourceTree = "<group>"; }; C0E720741281C828004EF533 /* EvaluateJSAfterRemovingPluginElement.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = EvaluateJSAfterRemovingPluginElement.cpp; sourceTree = "<group>"; }; C0EC3C9B12787F0500939164 /* NullNPPGetValuePointer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = NullNPPGetValuePointer.cpp; sourceTree = "<group>"; }; @@ -475,11 +483,13 @@ 1A215A6E11F25FF1008AD0F5 /* Tests */ = { isa = PBXGroup; children = ( + 1A31EB3613466AC100017372 /* mac */, 1A215A7511F26072008AD0F5 /* DocumentOpenInDestroyStream.cpp */, C0E720741281C828004EF533 /* EvaluateJSAfterRemovingPluginElement.cpp */, 1A3E28A91311D73B00501349 /* GetURLWithJavaScriptURLDestroyingPlugin.cpp */, 1AD4CB2012A6D1350027A7AF /* GetUserAgentWithNullNPPFromNPPNew.cpp */, 1ACF898B132EF41C00E915D4 /* NPDeallocateCalledBeforeNPShutdown.cpp */, + C031182A134E4A2B00919757 /* NPPSetWindowCalledDuringDestruction.cpp */, 1A24BAA8120734EE00FBB059 /* NPRuntimeObjectFromDestroyedPlugin.cpp */, 1AC77DCE120605B6005C19EF /* NPRuntimeRemoveProperty.cpp */, C0EC3C9B12787F0500939164 /* NullNPPGetValuePointer.cpp */, @@ -489,6 +499,14 @@ path = Tests; sourceTree = "<group>"; }; + 1A31EB3613466AC100017372 /* mac */ = { + isa = PBXGroup; + children = ( + 1A31EB3713466AC100017372 /* ConvertPoint.cpp */, + ); + path = mac; + sourceTree = "<group>"; + }; 9340995508540CAF007F3BC8 /* Products */ = { isa = PBXGroup; children = ( @@ -570,6 +588,8 @@ BCB284870CFA81ED007E533E /* PixelDump */ = { isa = PBXGroup; children = ( + 53CBB830134E42F3001CE6A4 /* CyclicRedundancyCheck.cpp */, + 53CBB831134E42F3001CE6A4 /* CyclicRedundancyCheck.h */, BCB284F30CFA84F2007E533E /* ImageDiffCG.cpp */, 8465E2C60FFA8DF2003B8342 /* PixelDumpSupport.cpp */, BCB2848A0CFA820F007E533E /* PixelDumpSupport.h */, @@ -600,6 +620,7 @@ BC0E24E00E2D9451001B6BC2 /* AccessibilityUIElement.h in Headers */, BCA18B380C9B021900114369 /* AppleScriptController.h in Headers */, A8B91BFF0CF522B4008F91FF /* CheckedMalloc.h in Headers */, + 53CBB833134E42F3001CE6A4 /* CyclicRedundancyCheck.h in Headers */, BCA18B7A0C9B08F100114369 /* DumpRenderTreeDraggingInfo.h in Headers */, A8D79CEA0FC28B2C004AC8FE /* DumpRenderTreeFileDraggingSource.h in Headers */, BCA18C0B0C9B59EF00114369 /* DumpRenderTreeMac.h in Headers */, @@ -774,6 +795,8 @@ 1AD4CB2212A6D1350027A7AF /* GetUserAgentWithNullNPPFromNPPNew.cpp in Sources */, 1A3E28AA1311D73B00501349 /* GetURLWithJavaScriptURLDestroyingPlugin.cpp in Sources */, 1ACF898D132EF41C00E915D4 /* NPDeallocateCalledBeforeNPShutdown.cpp in Sources */, + 1A31EB3813466AC100017372 /* ConvertPoint.cpp in Sources */, + C031182B134E4A2B00919757 /* NPPSetWindowCalledDuringDestruction.cpp in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -787,6 +810,7 @@ BC0E26150E2DA4C6001B6BC2 /* AccessibilityUIElementMac.mm in Sources */, BCA18B390C9B021900114369 /* AppleScriptController.m in Sources */, A8B91BFD0CF522B4008F91FF /* CheckedMalloc.cpp in Sources */, + 53CBB832134E42F3001CE6A4 /* CyclicRedundancyCheck.cpp in Sources */, BCA18C470C9B5B9400114369 /* DumpRenderTree.mm in Sources */, BCA18B7B0C9B08F100114369 /* DumpRenderTreeDraggingInfo.mm in Sources */, A8D79CEB0FC28B2C004AC8FE /* DumpRenderTreeFileDraggingSource.m in Sources */, diff --git a/Tools/DumpRenderTree/ForwardingHeaders/wtf/Alignment.h b/Tools/DumpRenderTree/ForwardingHeaders/wtf/Alignment.h new file mode 100644 index 0000000..e83483e --- /dev/null +++ b/Tools/DumpRenderTree/ForwardingHeaders/wtf/Alignment.h @@ -0,0 +1 @@ +#include <JavaScriptCore/Alignment.h> diff --git a/Tools/DumpRenderTree/ForwardingHeaders/wtf/DynamicAnnotations.h b/Tools/DumpRenderTree/ForwardingHeaders/wtf/DynamicAnnotations.h new file mode 100644 index 0000000..1280da8 --- /dev/null +++ b/Tools/DumpRenderTree/ForwardingHeaders/wtf/DynamicAnnotations.h @@ -0,0 +1 @@ +#include <JavaScriptCore/DynamicAnnotations.h> diff --git a/Tools/DumpRenderTree/LayoutTestController.cpp b/Tools/DumpRenderTree/LayoutTestController.cpp index 18b3dcd..3105ce4 100644 --- a/Tools/DumpRenderTree/LayoutTestController.cpp +++ b/Tools/DumpRenderTree/LayoutTestController.cpp @@ -44,6 +44,7 @@ LayoutTestController::LayoutTestController(const std::string& testPathOrURL, const std::string& expectedPixelHash) : m_dumpApplicationCacheDelegateCallbacks(false) + , m_dumpAsAudio(false) , m_dumpAsPDF(false) , m_dumpAsText(false) , m_dumpBackForwardList(false) @@ -315,6 +316,25 @@ static JSValueRef setCloseRemainingWindowsWhenCompleteCallback(JSContextRef cont return JSValueMakeUndefined(context); } +static JSValueRef setEncodedAudioDataCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + if (argumentCount < 1) + return JSValueMakeUndefined(context); + + JSRetainPtr<JSStringRef> encodedAudioData(Adopt, JSValueToStringCopy(context, arguments[0], exception)); + ASSERT(!*exception); + + size_t maxLength = JSStringGetMaximumUTF8CStringSize(encodedAudioData.get()); + OwnArrayPtr<char> encodedAudioDataBuffer = adoptArrayPtr(new char[maxLength + 1]); + JSStringGetUTF8CString(encodedAudioData.get(), encodedAudioDataBuffer.get(), maxLength + 1); + + LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject)); + controller->setEncodedAudioData(encodedAudioDataBuffer.get()); + controller->setDumpAsAudio(true); + + return JSValueMakeUndefined(context); +} + static JSValueRef testOnscreenCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) { LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject)); @@ -1687,6 +1707,14 @@ static JSValueRef setAsynchronousSpellCheckingEnabledCallback(JSContextRef conte return JSValueMakeUndefined(context); } +static JSValueRef shadowRootCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + if (argumentCount != 1) + return JSValueMakeUndefined(context); + LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject)); + return controller->shadowRoot(context, arguments[0]); +} + static JSValueRef showWebInspectorCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) { LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject)); @@ -2213,6 +2241,7 @@ JSStaticFunction* LayoutTestController::staticFunctions() { "setAlwaysAcceptCookies", setAlwaysAcceptCookiesCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, { "setAppCacheMaximumSize", setAppCacheMaximumSizeCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, { "setApplicationCacheOriginQuota", setApplicationCacheOriginQuotaCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "setEncodedAudioData", setEncodedAudioDataCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, { "setAuthenticationPassword", setAuthenticationPasswordCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, { "setAuthenticationUsername", setAuthenticationUsernameCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, { "setAuthorAndUserStylesEnabled", setAuthorAndUserStylesEnabledCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, @@ -2264,6 +2293,7 @@ JSStaticFunction* LayoutTestController::staticFunctions() { "setJavaScriptCanAccessClipboard", setJavaScriptCanAccessClipboardCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, { "setXSSAuditorEnabled", setXSSAuditorEnabledCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, { "setAsynchronousSpellCheckingEnabled", setAsynchronousSpellCheckingEnabledCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "shadowRoot", shadowRootCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, { "showWebInspector", showWebInspectorCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, { "testOnscreen", testOnscreenCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, { "testRepaint", testRepaintCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, diff --git a/Tools/DumpRenderTree/LayoutTestController.h b/Tools/DumpRenderTree/LayoutTestController.h index 4a6e59c..a429dbf 100644 --- a/Tools/DumpRenderTree/LayoutTestController.h +++ b/Tools/DumpRenderTree/LayoutTestController.h @@ -122,6 +122,7 @@ public: void setSpatialNavigationEnabled(bool enable); void setScrollbarPolicy(JSStringRef orientation, JSStringRef policy); void setEditingBehavior(const char* editingBehavior); + JSValueRef shadowRoot(JSContextRef, JSValueRef); void waitForPolicyDelegate(); size_t webHistoryItemCount(); @@ -133,6 +134,9 @@ public: bool elementDoesAutoCompleteForElementWithId(JSStringRef id); + bool dumpAsAudio() const { return m_dumpAsAudio; } + void setDumpAsAudio(bool dumpAsAudio) { m_dumpAsAudio = dumpAsAudio; } + bool dumpAsPDF() const { return m_dumpAsPDF; } void setDumpAsPDF(bool dumpAsPDF) { m_dumpAsPDF = dumpAsPDF; } @@ -262,6 +266,9 @@ public: const std::string& testPathOrURL() const { return m_testPathOrURL; } const std::string& expectedPixelHash() const { return m_expectedPixelHash; } + + const std::string& encodedAudioData() const { return m_encodedAudioData; } + void setEncodedAudioData(const std::string& encodedAudioData) { m_encodedAudioData = encodedAudioData; } bool pauseAnimationAtTimeOnElementWithId(JSStringRef animationName, double time, JSStringRef elementId); bool pauseTransitionAtTimeOnElementWithId(JSStringRef propertyName, double time, JSStringRef elementId); @@ -333,6 +340,7 @@ private: void setGeolocationPermissionCommon(bool allow); bool m_dumpApplicationCacheDelegateCallbacks; + bool m_dumpAsAudio; bool m_dumpAsPDF; bool m_dumpAsText; bool m_dumpBackForwardList; @@ -382,6 +390,9 @@ private: std::set<std::string> m_willSendRequestClearHeaders; + // base64 encoded WAV audio data is stored here. + std::string m_encodedAudioData; + // origins which have been granted desktop notification access std::vector<JSStringRef> m_desktopNotificationAllowedOrigins; diff --git a/Tools/DumpRenderTree/PixelDumpSupport.cpp b/Tools/DumpRenderTree/PixelDumpSupport.cpp index 352eaaa..24fbf4b 100644 --- a/Tools/DumpRenderTree/PixelDumpSupport.cpp +++ b/Tools/DumpRenderTree/PixelDumpSupport.cpp @@ -29,15 +29,17 @@ #include "config.h" #include "PixelDumpSupport.h" +#include "CyclicRedundancyCheck.h" #include "DumpRenderTree.h" #include "LayoutTestController.h" #include <cstdio> #include <wtf/Assertions.h> #include <wtf/RefPtr.h> +#include <wtf/Vector.h> -#if PLATFORM(CG) +#if USE(CG) #include "PixelDumpSupportCG.h" -#elif PLATFORM(CAIRO) +#elif USE(CAIRO) #include "PixelDumpSupportCairo.h" #endif @@ -69,16 +71,60 @@ void dumpWebViewAsPixelsAndCompareWithExpected(const std::string& expectedHash) } if (dumpImage) - dumpBitmap(context.get()); + dumpBitmap(context.get(), actualHash); } -void printPNG(const unsigned char* data, const size_t dataLength) +static void appendIntToVector(unsigned number, Vector<unsigned char>& vector) { + size_t offset = vector.size(); + vector.grow(offset + 4); + vector[offset] = ((number >> 24) & 0xff); + vector[offset + 1] = ((number >> 16) & 0xff); + vector[offset + 2] = ((number >> 8) & 0xff); + vector[offset + 3] = (number & 0xff); +} + +static void convertChecksumToPNGComment(const char* checksum, Vector<unsigned char>& bytesToAdd) +{ + // Chunks of PNG files are <length>, <type>, <data>, <crc>. + static const char textCommentPrefix[] = "\x00\x00\x00\x29tEXtchecksum\x00"; + static const size_t prefixLength = sizeof(textCommentPrefix) - 1; // The -1 is for the null at the end of the char[]. + static const size_t checksumLength = 32; + + bytesToAdd.append(textCommentPrefix, prefixLength); + bytesToAdd.append(checksum, checksumLength); + + Vector<unsigned char> dataToCrc; + dataToCrc.append(textCommentPrefix + 4, prefixLength - 4); // Don't include the chunk length in the crc. + dataToCrc.append(checksum, checksumLength); + unsigned crc32 = computeCrc(dataToCrc); + + appendIntToVector(crc32, bytesToAdd); +} + +static size_t offsetAfterIHDRChunk(const unsigned char* data, const size_t dataLength) +{ + const int pngHeaderLength = 8; + const int pngIHDRChunkLength = 25; // chunk length + "IHDR" + 13 bytes of data + checksum + return pngHeaderLength + pngIHDRChunkLength; +} + +void printPNG(const unsigned char* data, const size_t dataLength, const char* checksum) +{ + Vector<unsigned char> bytesToAdd; + convertChecksumToPNGComment(checksum, bytesToAdd); + printf("Content-Type: %s\n", "image/png"); - printf("Content-Length: %lu\n", static_cast<unsigned long>(dataLength)); + printf("Content-Length: %lu\n", static_cast<unsigned long>(dataLength + bytesToAdd.size())); + + size_t insertOffset = offsetAfterIHDRChunk(data, dataLength); + + fwrite(data, 1, insertOffset, stdout); + fwrite(bytesToAdd.data(), 1, bytesToAdd.size(), stdout); const size_t bytesToWriteInOneChunk = 1 << 15; - size_t dataRemainingToWrite = dataLength; + data += insertOffset; + size_t dataRemainingToWrite = dataLength - insertOffset; while (dataRemainingToWrite) { size_t bytesToWriteInThisChunk = std::min(dataRemainingToWrite, bytesToWriteInOneChunk); size_t bytesWritten = fwrite(data, 1, bytesToWriteInThisChunk, stdout); diff --git a/Tools/DumpRenderTree/PixelDumpSupport.h b/Tools/DumpRenderTree/PixelDumpSupport.h index e172a83..87e6402 100644 --- a/Tools/DumpRenderTree/PixelDumpSupport.h +++ b/Tools/DumpRenderTree/PixelDumpSupport.h @@ -38,9 +38,9 @@ class BitmapContext; void computeMD5HashStringForBitmapContext(BitmapContext*, char hashString[33]); PassRefPtr<BitmapContext> createPagedBitmapContext(); PassRefPtr<BitmapContext> createBitmapContextFromWebView(bool onscreen, bool incrementalRepaint, bool sweepHorizontally, bool drawSelectionRect); -void dumpBitmap(BitmapContext*); +void dumpBitmap(BitmapContext*, const char* checksum); void dumpWebViewAsPixelsAndCompareWithExpected(const std::string& expectedHash); -void printPNG(const unsigned char* data, const size_t dataLength); +void printPNG(const unsigned char* data, const size_t dataLength, const char* checksum); #if PLATFORM(MAC) diff --git a/Tools/DumpRenderTree/TestNetscapePlugIn/PluginObject.cpp b/Tools/DumpRenderTree/TestNetscapePlugIn/PluginObject.cpp index 24ee12c..75b848b 100644 --- a/Tools/DumpRenderTree/TestNetscapePlugIn/PluginObject.cpp +++ b/Tools/DumpRenderTree/TestNetscapePlugIn/PluginObject.cpp @@ -73,14 +73,10 @@ static void pluginLogWithWindowObjectVariableArgs(NPObject* windowObject, NPP in pluginLogWithWindowObject(windowObject, instance, message); } -// Helper function to log to the console object. -void pluginLog(NPP instance, const char* format, ...) +void pluginLogWithArguments(NPP instance, const char* format, va_list args) { - va_list args; - va_start(args, format); char message[2048] = "PLUGIN: "; vsprintf(message + strlen(message), format, args); - va_end(args); NPObject* windowObject = 0; NPError error = browser->getvalue(instance, NPNVWindowNPObject, &windowObject); @@ -93,6 +89,15 @@ void pluginLog(NPP instance, const char* format, ...) browser->releaseobject(windowObject); } +// Helper function to log to the console object. +void pluginLog(NPP instance, const char* format, ...) +{ + va_list args; + va_start(args, format); + pluginLogWithArguments(instance, format, args); + va_end(args); +} + static void pluginInvalidate(NPObject*); static bool pluginHasProperty(NPObject*, NPIdentifier name); static bool pluginHasMethod(NPObject*, NPIdentifier name); diff --git a/Tools/DumpRenderTree/TestNetscapePlugIn/PluginObject.h b/Tools/DumpRenderTree/TestNetscapePlugIn/PluginObject.h index c264e49..efca1d5 100644 --- a/Tools/DumpRenderTree/TestNetscapePlugIn/PluginObject.h +++ b/Tools/DumpRenderTree/TestNetscapePlugIn/PluginObject.h @@ -27,6 +27,7 @@ #define PluginObject_h #include <WebKit/npfunctions.h> +#include <stdarg.h> #if defined(XP_MACOSX) #if !defined(MAC_OS_X_VERSION_10_5) || MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_5 @@ -87,6 +88,7 @@ extern void handleCallback(PluginObject* object, const char *url, NPReason reaso extern void notifyStream(PluginObject* object, const char *url, const char *headers); extern void testNPRuntime(NPP npp); extern void pluginLog(NPP instance, const char* format, ...); +extern void pluginLogWithArguments(NPP instance, const char* format, va_list args); extern bool testDocumentOpen(NPP npp); extern bool testWindowOpen(NPP npp); diff --git a/Tools/DumpRenderTree/TestNetscapePlugIn/PluginTest.cpp b/Tools/DumpRenderTree/TestNetscapePlugIn/PluginTest.cpp index 98ef799..9181a86 100644 --- a/Tools/DumpRenderTree/TestNetscapePlugIn/PluginTest.cpp +++ b/Tools/DumpRenderTree/TestNetscapePlugIn/PluginTest.cpp @@ -25,6 +25,7 @@ #include "PluginTest.h" +#include "PluginObject.h" #include <assert.h> #include <string.h> @@ -69,6 +70,18 @@ void PluginTest::registerNPShutdownFunction(void (*func)()) shutdownFunction = func; } +void PluginTest::indicateTestFailure() +{ + // This should really be an assert, but there's no way for the test framework + // to know that the plug-in process crashed, so we'll just sleep for a while + // to ensure that the test times out. +#if defined(XP_WIN) + ::Sleep(100000); +#else + sleep(1000); +#endif +} + NPError PluginTest::NPP_New(NPMIMEType pluginType, uint16_t mode, int16_t argc, char *argn[], char *argv[], NPSavedData *saved) { return NPERR_NO_ERROR; @@ -135,6 +148,13 @@ bool PluginTest::NPN_RemoveProperty(NPObject* npObject, NPIdentifier propertyNam return browser->removeproperty(m_npp, npObject, propertyName); } +#ifdef XP_MACOSX +bool PluginTest::NPN_ConvertPoint(double sourceX, double sourceY, NPCoordinateSpace sourceSpace, double *destX, double *destY, NPCoordinateSpace destSpace) +{ + return browser->convertpoint(m_npp, sourceX, sourceY, sourceSpace, destX, destY, destSpace); +} +#endif + void PluginTest::executeScript(const char* script) { NPObject* windowScriptObject; @@ -149,6 +169,14 @@ void PluginTest::executeScript(const char* script) browser->releasevariantvalue(&browserResult); } +void PluginTest::log(const char* format, ...) +{ + va_list args; + va_start(args, format); + pluginLogWithArguments(m_npp, format, args); + va_end(args); +} + void PluginTest::waitUntilDone() { executeScript("layoutTestController.waitUntilDone()"); diff --git a/Tools/DumpRenderTree/TestNetscapePlugIn/PluginTest.h b/Tools/DumpRenderTree/TestNetscapePlugIn/PluginTest.h index cf94165..b704014 100644 --- a/Tools/DumpRenderTree/TestNetscapePlugIn/PluginTest.h +++ b/Tools/DumpRenderTree/TestNetscapePlugIn/PluginTest.h @@ -73,11 +73,17 @@ public: NPError NPN_GetValue(NPNVariable, void* value); NPObject* NPN_CreateObject(NPClass*); bool NPN_RemoveProperty(NPObject*, NPIdentifier propertyName); - +#ifdef XP_MACOSX + bool NPN_ConvertPoint(double sourceX, double sourceY, NPCoordinateSpace sourceSpace, double *destX, double *destY, NPCoordinateSpace destSpace); +#endif + void executeScript(const char*); + void log(const char* format, ...); void registerNPShutdownFunction(void (*)()); + static void indicateTestFailure(); + template<typename TestClassTy> class Register { public: Register(const std::string& identifier) diff --git a/Tools/DumpRenderTree/TestNetscapePlugIn/Tests/NPDeallocateCalledBeforeNPShutdown.cpp b/Tools/DumpRenderTree/TestNetscapePlugIn/Tests/NPDeallocateCalledBeforeNPShutdown.cpp index c53ec97..91f47af 100644 --- a/Tools/DumpRenderTree/TestNetscapePlugIn/Tests/NPDeallocateCalledBeforeNPShutdown.cpp +++ b/Tools/DumpRenderTree/TestNetscapePlugIn/Tests/NPDeallocateCalledBeforeNPShutdown.cpp @@ -42,16 +42,8 @@ private: public: ~TestObject() { - // This should really be an assert, but there's no way for the test framework - // to know that the plug-in process crashed, so we'll just sleep for a while - // to ensure that the test times out. - if (wasShutdownCalled) { -#if defined(XP_WIN) - ::Sleep(100000); -#else - sleep(1000); -#endif - } + if (wasShutdownCalled) + indicateTestFailure(); } }; diff --git a/Tools/DumpRenderTree/TestNetscapePlugIn/Tests/NPPSetWindowCalledDuringDestruction.cpp b/Tools/DumpRenderTree/TestNetscapePlugIn/Tests/NPPSetWindowCalledDuringDestruction.cpp new file mode 100644 index 0000000..ba63243 --- /dev/null +++ b/Tools/DumpRenderTree/TestNetscapePlugIn/Tests/NPPSetWindowCalledDuringDestruction.cpp @@ -0,0 +1,125 @@ +/* + * Copyright (C) 2011 Apple 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. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. 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 INC. 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. + */ + +#include "PluginTest.h" + +#include "PluginObject.h" + +using namespace std; + +// NPP_SetWindow should be called with a null window handle as destruction begins on non-Mac platforms. + +class NPPSetWindowCalledDuringDestruction : public PluginTest { +public: + NPPSetWindowCalledDuringDestruction(NPP, const string& identifier); + + void setWillBeDestroyed() { m_willBeDestroyed = true; } + +private: + struct ScriptObject : Object<ScriptObject> { + bool hasMethod(NPIdentifier); + bool invoke(NPIdentifier, const NPVariant*, uint32_t, NPVariant*); + }; + + virtual NPError NPP_GetValue(NPPVariable, void*); + virtual NPError NPP_SetWindow(NPP, NPWindow*); + virtual NPError NPP_Destroy(NPSavedData**); + + bool m_willBeDestroyed; + bool m_setWindowCalledBeforeDestruction; + bool m_setWindowCalledDuringDestruction; +}; + +static PluginTest::Register<NPPSetWindowCalledDuringDestruction> registrar("npp-set-window-called-during-destruction"); + +NPPSetWindowCalledDuringDestruction::NPPSetWindowCalledDuringDestruction(NPP npp, const string& identifier) + : PluginTest(npp, identifier) + , m_willBeDestroyed(false) + , m_setWindowCalledBeforeDestruction(false) + , m_setWindowCalledDuringDestruction(false) +{ +} + +NPError NPPSetWindowCalledDuringDestruction::NPP_GetValue(NPPVariable variable, void* value) +{ + if (variable != NPPVpluginScriptableNPObject) + return NPERR_GENERIC_ERROR; + + *static_cast<NPObject**>(value) = ScriptObject::create(this); + + return NPERR_NO_ERROR; +} + +NPError NPPSetWindowCalledDuringDestruction::NPP_SetWindow(NPP, NPWindow* window) +{ + if (m_willBeDestroyed) { + m_setWindowCalledDuringDestruction = true; + if (!m_setWindowCalledBeforeDestruction) { + log("Fail: setWillBeDestroyed() was called before the initial NPP_SetWindow call"); + return NPERR_NO_ERROR; + } +#ifndef XP_MACOSX + if (window->window) + log("Fail: NPP_SetWindow passed a non-null window during plugin destruction"); +#endif + return NPERR_NO_ERROR; + } + + if (m_setWindowCalledBeforeDestruction) { + log("Fail: NPP_SetWindow called more than once before plugin destruction"); + return NPERR_NO_ERROR; + } + + m_setWindowCalledBeforeDestruction = true; + return NPERR_NO_ERROR; +} + +NPError NPPSetWindowCalledDuringDestruction::NPP_Destroy(NPSavedData**) +{ +#ifdef XP_MACOSX + bool shouldHaveBeenCalledDuringDestruction = false; +#else + bool shouldHaveBeenCalledDuringDestruction = true; +#endif + + if (m_setWindowCalledDuringDestruction == shouldHaveBeenCalledDuringDestruction) + log("Success: NPP_SetWindow %s called during plugin destruction", shouldHaveBeenCalledDuringDestruction ? "was" : "was not"); + else + log("Fail: NPP_SetWindow %s called during plugin destruction", shouldHaveBeenCalledDuringDestruction ? "was not" : "was"); + + return NPERR_NO_ERROR; +} + +bool NPPSetWindowCalledDuringDestruction::ScriptObject::hasMethod(NPIdentifier methodName) +{ + return methodName == pluginTest()->NPN_GetStringIdentifier("setWillBeDestroyed"); +} + +bool NPPSetWindowCalledDuringDestruction::ScriptObject::invoke(NPIdentifier identifier, const NPVariant*, uint32_t, NPVariant*) +{ + assert(identifier == pluginTest()->NPN_GetStringIdentifier("setWillBeDestroyed")); + static_cast<NPPSetWindowCalledDuringDestruction*>(pluginTest())->setWillBeDestroyed(); + return true; +} diff --git a/Tools/DumpRenderTree/TestNetscapePlugIn/Tests/mac/ConvertPoint.cpp b/Tools/DumpRenderTree/TestNetscapePlugIn/Tests/mac/ConvertPoint.cpp new file mode 100644 index 0000000..7cef707 --- /dev/null +++ b/Tools/DumpRenderTree/TestNetscapePlugIn/Tests/mac/ConvertPoint.cpp @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2010 Apple 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. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. 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 INC. 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. + */ + +#include "PluginTest.h" + +using namespace std; + +// Test that NPN_ConvertPoint converts correctly. +class ConvertPoint : public PluginTest { +public: + ConvertPoint(NPP npp, const string& identifier) + : PluginTest(npp, identifier) + { + } + + bool testConvert(double x, double y, NPCoordinateSpace sourceSpace, NPCoordinateSpace destSpace) + { + // First convert from src to dest. + double destX, destY; + if (!NPN_ConvertPoint(x, y, sourceSpace, &destX, &destY, destSpace)) + return false; + + // Then convert back to src + double srcX, srcY; + if (!NPN_ConvertPoint(destX, destY, destSpace, &srcX, &srcY, sourceSpace)) + return false; + + + // Then compare. + if (srcX != x || srcY != y) + return false; + + return true; + } + + bool testConvert() + { + static const NPCoordinateSpace spaces[] = { NPCoordinateSpacePlugin, NPCoordinateSpaceWindow, NPCoordinateSpaceFlippedWindow, NPCoordinateSpaceScreen, NPCoordinateSpaceFlippedScreen }; + + static const size_t numSpaces = sizeof(spaces) / sizeof(spaces[0]); + for (size_t i = 0; i < numSpaces; ++i) { + for (size_t j = 0; j < numSpaces; ++j) { + if (!testConvert(1234, 5678, spaces[i], spaces[j])) + return false; + } + } + return true; + } +private: + virtual NPError NPP_New(NPMIMEType pluginType, uint16_t mode, int16_t argc, char *argn[], char *argv[], NPSavedData *saved) + { + if (testConvert()) + executeScript("document.getElementById('result').innerHTML = 'SUCCESS!'"); + + return NPERR_NO_ERROR; + } +}; + +static PluginTest::Register<ConvertPoint> convertPoint("convert-point"); diff --git a/Tools/DumpRenderTree/TestNetscapePlugIn/win/TestNetscapePlugin.vcproj b/Tools/DumpRenderTree/TestNetscapePlugIn/win/TestNetscapePlugin.vcproj index 5856985..b7bf54b 100644 --- a/Tools/DumpRenderTree/TestNetscapePlugIn/win/TestNetscapePlugin.vcproj +++ b/Tools/DumpRenderTree/TestNetscapePlugIn/win/TestNetscapePlugin.vcproj @@ -410,6 +410,10 @@ > </File> <File + RelativePath="..\Tests\NPPSetWindowCalledDuringDestruction.cpp" + > + </File> + <File RelativePath="..\Tests\NPRuntimeObjectFromDestroyedPlugin.cpp" > </File> diff --git a/Tools/DumpRenderTree/TestNetscapePlugIn/win/TestNetscapePluginProduction.vsprops b/Tools/DumpRenderTree/TestNetscapePlugIn/win/TestNetscapePluginProduction.vsprops index 4a65c62..8d64b41 100644 --- a/Tools/DumpRenderTree/TestNetscapePlugIn/win/TestNetscapePluginProduction.vsprops +++ b/Tools/DumpRenderTree/TestNetscapePlugIn/win/TestNetscapePluginProduction.vsprops @@ -5,7 +5,7 @@ Name="TestNetscapePluginProduction" InheritedPropertySheets=" $(WebKitVSPropsRedirectionDir)..\..\..\..\WebKitLibraries\win\tools\vsprops\common.vsprops; - $(WebKitVSPropsRedirectionDir)..\..\..\..\WebKitLibraries\win\tools\vsprops\release.vsprops; + $(WebKitVSPropsRedirectionDir)..\..\..\..\WebKitLibraries\win\tools\vsprops\releaseproduction.vsprops; $(WebKitVSPropsRedirectionDir)..\..\..\..\WebKitLibraries\win\tools\vsprops\production.vsprops; .\TestNetscapePluginCommon.vsprops" > diff --git a/Tools/DumpRenderTree/TestNetscapePlugIn/win/TestNetscapePluginRelease.vsprops b/Tools/DumpRenderTree/TestNetscapePlugIn/win/TestNetscapePluginRelease.vsprops index c410e11..1aeb953 100644 --- a/Tools/DumpRenderTree/TestNetscapePlugIn/win/TestNetscapePluginRelease.vsprops +++ b/Tools/DumpRenderTree/TestNetscapePlugIn/win/TestNetscapePluginRelease.vsprops @@ -5,6 +5,7 @@ Name="TestNetscapePluginRelease" InheritedPropertySheets=" $(WebKitVSPropsRedirectionDir)..\..\..\..\WebKitLibraries\win\tools\vsprops\common.vsprops; + $(WebKitVSPropsRedirectionDir)..\..\..\..\WebKitLibraries\win\tools\vsprops\releaseproduction.vsprops; $(WebKitVSPropsRedirectionDir)..\..\..\..\WebKitLibraries\win\tools\vsprops\release.vsprops; .\TestNetscapePluginCommon.vsprops" > diff --git a/Tools/DumpRenderTree/TestNetscapePlugIn/win/TestNetscapePluginReleaseCairoCFLite.vsprops b/Tools/DumpRenderTree/TestNetscapePlugIn/win/TestNetscapePluginReleaseCairoCFLite.vsprops index eb51008..03651ab 100644 --- a/Tools/DumpRenderTree/TestNetscapePlugIn/win/TestNetscapePluginReleaseCairoCFLite.vsprops +++ b/Tools/DumpRenderTree/TestNetscapePlugIn/win/TestNetscapePluginReleaseCairoCFLite.vsprops @@ -5,6 +5,7 @@ Name="TestNetscapePluginReleaseCairoCFLite" InheritedPropertySheets=" $(WebKitVSPropsRedirectionDir)..\..\..\..\WebKitLibraries\win\tools\vsprops\common.vsprops; + $(WebKitVSPropsRedirectionDir)..\..\..\..\WebKitLibraries\win\tools\vsprops\releaseproduction.vsprops; $(WebKitVSPropsRedirectionDir)..\..\..\..\WebKitLibraries\win\tools\vsprops\release.vsprops; $(WebKitVSPropsRedirectionDir)..\..\..\..\WebKitLibraries\win\tools\vsprops\WinCairo.vsprops; .\TestNetscapePluginCommon.vsprops" diff --git a/Tools/DumpRenderTree/cairo/PixelDumpSupportCairo.cpp b/Tools/DumpRenderTree/cairo/PixelDumpSupportCairo.cpp index 7de019d..c10a3a7 100644 --- a/Tools/DumpRenderTree/cairo/PixelDumpSupportCairo.cpp +++ b/Tools/DumpRenderTree/cairo/PixelDumpSupportCairo.cpp @@ -49,7 +49,7 @@ static cairo_status_t writeFunction(void* closure, const unsigned char* data, un return CAIRO_STATUS_SUCCESS; } -static void printPNG(cairo_surface_t* image) +static void printPNG(cairo_surface_t* image, const char* checksum) { Vector<unsigned char> pixelData; // Only PNG output is supported for now. @@ -58,7 +58,7 @@ static void printPNG(cairo_surface_t* image) const size_t dataLength = pixelData.size(); const unsigned char* data = pixelData.data(); - printPNG(data, dataLength); + printPNG(data, dataLength, checksum); } void computeMD5HashStringForBitmapContext(BitmapContext* context, char hashString[33]) @@ -86,8 +86,8 @@ void computeMD5HashStringForBitmapContext(BitmapContext* context, char hashStrin hash[8], hash[9], hash[10], hash[11], hash[12], hash[13], hash[14], hash[15]); } -void dumpBitmap(BitmapContext* context) +void dumpBitmap(BitmapContext* context, const char* checksum) { cairo_surface_t* surface = cairo_get_target(context->cairoContext()); - printPNG(surface); + printPNG(surface, checksum); } diff --git a/Tools/DumpRenderTree/cg/PixelDumpSupportCG.cpp b/Tools/DumpRenderTree/cg/PixelDumpSupportCG.cpp index 5cf32f1..bf59b03 100644 --- a/Tools/DumpRenderTree/cg/PixelDumpSupportCG.cpp +++ b/Tools/DumpRenderTree/cg/PixelDumpSupportCG.cpp @@ -55,7 +55,7 @@ using namespace std; static const CFStringRef kUTTypePNG = CFSTR("public.png"); #endif -static void printPNG(CGImageRef image) +static void printPNG(CGImageRef image, const char* checksum) { RetainPtr<CFMutableDataRef> imageData(AdoptCF, CFDataCreateMutable(0, 0)); RetainPtr<CGImageDestinationRef> imageDest(AdoptCF, CGImageDestinationCreateWithData(imageData.get(), kUTTypePNG, 1, 0)); @@ -65,7 +65,7 @@ static void printPNG(CGImageRef image) const UInt8* data = CFDataGetBytePtr(imageData.get()); CFIndex dataLength = CFDataGetLength(imageData.get()); - printPNG(static_cast<const unsigned char*>(data), static_cast<size_t>(dataLength)); + printPNG(static_cast<const unsigned char*>(data), static_cast<size_t>(dataLength), checksum); } void computeMD5HashStringForBitmapContext(BitmapContext* context, char hashString[33]) @@ -106,8 +106,8 @@ void computeMD5HashStringForBitmapContext(BitmapContext* context, char hashStrin snprintf(hashString, 33, "%s%02x", hashString, hash[i]); } -void dumpBitmap(BitmapContext* context) +void dumpBitmap(BitmapContext* context, const char* checksum) { RetainPtr<CGImageRef> image(AdoptCF, CGBitmapContextCreateImage(context->cgContext())); - printPNG(image.get()); + printPNG(image.get(), checksum); } diff --git a/Tools/DumpRenderTree/chromium/LayoutTestController.cpp b/Tools/DumpRenderTree/chromium/LayoutTestController.cpp index d91cd6e..72c05b1 100644 --- a/Tools/DumpRenderTree/chromium/LayoutTestController.cpp +++ b/Tools/DumpRenderTree/chromium/LayoutTestController.cpp @@ -214,6 +214,7 @@ LayoutTestController::LayoutTestController(TestShell* shell) bindProperty("globalFlag", &m_globalFlag); // webHistoryItemCount is used by tests in LayoutTests\http\tests\history bindProperty("webHistoryItemCount", &m_webHistoryItemCount); + bindProperty("titleTextDirection", &m_titleTextDirection); } LayoutTestController::~LayoutTestController() @@ -573,6 +574,7 @@ void LayoutTestController::reset() m_deferMainResourceDataLoad = true; m_globalFlag.set(false); m_webHistoryItemCount.set(0); + m_titleTextDirection.set("ltr"); m_userStyleSheetLocation = WebURL(); webkit_support::SetAcceptAllCookies(false); diff --git a/Tools/DumpRenderTree/chromium/LayoutTestController.h b/Tools/DumpRenderTree/chromium/LayoutTestController.h index a9c6ce4..5df7153 100644 --- a/Tools/DumpRenderTree/chromium/LayoutTestController.h +++ b/Tools/DumpRenderTree/chromium/LayoutTestController.h @@ -44,6 +44,7 @@ #include "CppBoundClass.h" #include "Task.h" #include "WebString.h" +#include "WebTextDirection.h" #include "WebURL.h" #include <wtf/Deque.h> #include <wtf/OwnPtr.h> @@ -391,6 +392,10 @@ public: bool stopProvisionalFrameLoads() { return m_stopProvisionalFrameLoads; } bool deferMainResourceDataLoad() { return m_deferMainResourceDataLoad; } void setShowDebugLayerTree(bool value) { m_showDebugLayerTree = value; } + void setTitleTextDirection(WebKit::WebTextDirection dir) + { + m_titleTextDirection.set(dir == WebKit::WebTextDirectionLeftToRight ? "ltr" : "rtl"); + } bool testRepaint() const { return m_testRepaint; } bool sweepHorizontally() const { return m_sweepHorizontally; } @@ -574,6 +579,9 @@ private: // Bound variable counting the number of top URLs visited. CppVariant m_webHistoryItemCount; + // Bound variable tracking the directionality of the <title> tag. + CppVariant m_titleTextDirection; + WebKit::WebURL m_userStyleSheetLocation; OwnPtr<WebKit::WebSpeechInputControllerMock> m_speechInputControllerMock; diff --git a/Tools/DumpRenderTree/chromium/TestShell.cpp b/Tools/DumpRenderTree/chromium/TestShell.cpp index 4790509..4a092e7 100644 --- a/Tools/DumpRenderTree/chromium/TestShell.cpp +++ b/Tools/DumpRenderTree/chromium/TestShell.cpp @@ -50,7 +50,6 @@ #include "WebURLResponse.h" #include "WebView.h" #include "WebViewHost.h" -#include "skia/ext/bitmap_platform_device.h" #include "skia/ext/platform_canvas.h" #include "webkit/support/webkit_support.h" #include "webkit/support/webkit_support_gfx.h" @@ -77,6 +76,21 @@ static const char fileTestPrefix[] = "(file test):"; static const char dataUrlPattern[] = "data:"; static const string::size_type dataUrlPatternSize = sizeof(dataUrlPattern) - 1; +// FIXME: Move this to a common place so that it can be shared with +// WebCore::TransparencyWin::makeLayerOpaque(). +static void makeCanvasOpaque(SkCanvas* canvas) +{ + const SkBitmap& bitmap = canvas->getTopDevice()->accessBitmap(true); + ASSERT(bitmap.config() == SkBitmap::kARGB_8888_Config); + + SkAutoLockPixels lock(bitmap); + for (int y = 0; y < bitmap.height(); y++) { + uint32_t* row = bitmap.getAddr32(0, y); + for (int x = 0; x < bitmap.width(); x++) + row[x] |= 0xFF000000; // Set alpha bits to 1. + } +} + TestShell::TestShell(bool testShellMode) : m_testIsPending(false) , m_testIsPreparing(false) @@ -516,14 +530,8 @@ void TestShell::dump() fflush(stderr); } -void TestShell::dumpImage(skia::PlatformCanvas* canvas) const +void TestShell::dumpImage(SkCanvas* canvas) const { - skia::BitmapPlatformDevice& device = - static_cast<skia::BitmapPlatformDevice&>(canvas->getTopPlatformDevice()); - const SkBitmap& sourceBitmap = device.accessBitmap(false); - - SkAutoLockPixels sourceBitmapLock(sourceBitmap); - // Fix the alpha. The expected PNGs on Mac have an alpha channel, so we want // to keep it. On Windows, the alpha channel is wrong since text/form control // drawing may have erased it in a few places. So on Windows we force it to @@ -533,9 +541,12 @@ void TestShell::dumpImage(skia::PlatformCanvas* canvas) const bool discardTransparency = false; #else bool discardTransparency = true; - device.makeOpaque(0, 0, sourceBitmap.width(), sourceBitmap.height()); + makeCanvasOpaque(canvas); #endif + const SkBitmap& sourceBitmap = canvas->getTopDevice()->accessBitmap(false); + SkAutoLockPixels sourceBitmapLock(sourceBitmap); + // Compute MD5 sum. MD5 digester; Vector<uint8_t, 16> digestValue; diff --git a/Tools/DumpRenderTree/chromium/TestShell.h b/Tools/DumpRenderTree/chromium/TestShell.h index d84d642..10d6909 100644 --- a/Tools/DumpRenderTree/chromium/TestShell.h +++ b/Tools/DumpRenderTree/chromium/TestShell.h @@ -54,9 +54,6 @@ class WebNotificationPresenter; class WebView; class WebURL; } -namespace skia { -class PlatformCanvas; -} class DRTDevToolsAgent; class DRTDevToolsCallArgs; @@ -182,7 +179,7 @@ private: void resetWebSettings(WebKit::WebView&); void dump(); std::string dumpAllBackForwardLists(); - void dumpImage(skia::PlatformCanvas*) const; + void dumpImage(SkCanvas*) const; bool m_testIsPending; bool m_testIsPreparing; diff --git a/Tools/DumpRenderTree/chromium/WebPreferences.cpp b/Tools/DumpRenderTree/chromium/WebPreferences.cpp index 84f84b6..c609397 100644 --- a/Tools/DumpRenderTree/chromium/WebPreferences.cpp +++ b/Tools/DumpRenderTree/chromium/WebPreferences.cpp @@ -165,5 +165,8 @@ void WebPreferences::applyTo(WebView* webView) settings->setUsesEncodingDetector(false); settings->setImagesEnabled(true); settings->setInteractiveFormValidationEnabled(true); + // Enable fullscreen so the fullscreen layout tests can run. + settings->setFullScreenEnabled(true); + settings->setValidationMessageTimerMagnification(-1); } diff --git a/Tools/DumpRenderTree/chromium/WebThemeControlDRTWin.cpp b/Tools/DumpRenderTree/chromium/WebThemeControlDRTWin.cpp index b1d9fa1..a2dda1d 100755 --- a/Tools/DumpRenderTree/chromium/WebThemeControlDRTWin.cpp +++ b/Tools/DumpRenderTree/chromium/WebThemeControlDRTWin.cpp @@ -46,7 +46,6 @@ #include <wtf/Assertions.h> using namespace std; -using namespace skia; static const SkColor edgeColor = SK_ColorBLACK; static const SkColor readOnlyColor = SkColorSetRGB(0xe9, 0xc2, 0xa6); @@ -93,7 +92,7 @@ static SkIRect validate(const SkIRect& rect, WebThemeControlDRTWin::Type ctype) // WebThemeControlDRTWin -WebThemeControlDRTWin::WebThemeControlDRTWin(PlatformCanvas* canvas, +WebThemeControlDRTWin::WebThemeControlDRTWin(SkCanvas* canvas, const SkIRect& irect, Type ctype, State cstate) @@ -304,7 +303,7 @@ void WebThemeControlDRTWin::draw() // Indents for the the slider track. const int sliderIndent = 2; - m_canvas->beginPlatformPaint(); + skia::BeginPlatformPaint(m_canvas); switch (m_type) { case UnknownType: @@ -475,7 +474,7 @@ void WebThemeControlDRTWin::draw() } markState(); - m_canvas->endPlatformPaint(); + skia::EndPlatformPaint(m_canvas); } // Because rendering a text field is dependent on input @@ -485,7 +484,7 @@ void WebThemeControlDRTWin::drawTextField(bool drawEdges, bool fillContentArea, { SkPaint paint; - m_canvas->beginPlatformPaint(); + skia::BeginPlatformPaint(m_canvas); if (fillContentArea) { paint.setColor(color); paint.setStyle(SkPaint::kFill_Style); @@ -498,14 +497,14 @@ void WebThemeControlDRTWin::drawTextField(bool drawEdges, bool fillContentArea, } markState(); - m_canvas->endPlatformPaint(); + skia::EndPlatformPaint(m_canvas); } void WebThemeControlDRTWin::drawProgressBar(const SkIRect& fillRect) { SkPaint paint; - m_canvas->beginPlatformPaint(); + skia::BeginPlatformPaint(m_canvas); paint.setColor(m_bgColor); paint.setStyle(SkPaint::kFill_Style); m_canvas->drawIRect(m_irect, paint); @@ -518,6 +517,6 @@ void WebThemeControlDRTWin::drawProgressBar(const SkIRect& fillRect) m_canvas->drawIRect(tofill, paint); markState(); - m_canvas->endPlatformPaint(); + skia::EndPlatformPaint(m_canvas); } diff --git a/Tools/DumpRenderTree/chromium/WebThemeControlDRTWin.h b/Tools/DumpRenderTree/chromium/WebThemeControlDRTWin.h index ede1458..6448dc6 100644 --- a/Tools/DumpRenderTree/chromium/WebThemeControlDRTWin.h +++ b/Tools/DumpRenderTree/chromium/WebThemeControlDRTWin.h @@ -120,12 +120,9 @@ public: ProgressBarType }; - // canvas is the canvas to draw onto, and rect gives the size of the - // control. ctype and cstate specify the type and state of the control. - WebThemeControlDRTWin(skia::PlatformCanvas* canvas, - const SkIRect& rect, - Type ctype, - State cstate); + // Constructs a control of the given size, type and state to draw + // on to the given canvas. + WebThemeControlDRTWin(SkCanvas*, const SkIRect&, Type, State); ~WebThemeControlDRTWin(); // Draws the control. @@ -184,7 +181,7 @@ private: // color is which. void markState(); - skia::PlatformCanvas* m_canvas; + SkCanvas* m_canvas; const SkIRect m_irect; const Type m_type; const State m_state; diff --git a/Tools/DumpRenderTree/chromium/WebViewHost.cpp b/Tools/DumpRenderTree/chromium/WebViewHost.cpp index 97c00e2..ae4a1b1 100644 --- a/Tools/DumpRenderTree/chromium/WebViewHost.cpp +++ b/Tools/DumpRenderTree/chromium/WebViewHost.cpp @@ -66,7 +66,6 @@ using namespace WebCore; using namespace WebKit; -using namespace skia; using namespace std; static const int screenWidth = 1920; @@ -406,7 +405,7 @@ bool WebViewHost::handleCurrentKeyboardEvent() return frame->executeCommand(WebString::fromUTF8(m_editCommandName), WebString::fromUTF8(m_editCommandValue)); } -void WebViewHost::spellCheck(const WebString& text, int& misspelledOffset, int& misspelledLength) +void WebViewHost::spellCheck(const WebString& text, int& misspelledOffset, int& misspelledLength, WebVector<WebString>* optionalSuggestions) { // Check the spelling of the given text. m_spellcheck.spellCheckWord(text, &misspelledOffset, &misspelledLength); @@ -933,7 +932,7 @@ void WebViewHost::didClearWindowObject(WebFrame* frame) m_shell->bindJSObjectsToWindow(frame); } -void WebViewHost::didReceiveTitle(WebFrame* frame, const WebString& title) +void WebViewHost::didReceiveTitle(WebFrame* frame, const WebString& title, WebTextDirection direction) { WebCString title8 = title.utf8(); @@ -946,6 +945,7 @@ void WebViewHost::didReceiveTitle(WebFrame* frame, const WebString& title) printf("TITLE CHANGED: %s\n", title8.data()); setPageTitle(title); + layoutTestController()->setTitleTextDirection(direction); } void WebViewHost::didFinishDocumentLoad(WebFrame* frame) @@ -1470,8 +1470,9 @@ void WebViewHost::paintRect(const WebRect& rect) ASSERT(!m_isPainting); ASSERT(canvas()); m_isPainting = true; -#if PLATFORM(CG) - webWidget()->paint(canvas()->getTopPlatformDevice().GetBitmapContext(), rect); +#if USE(CG) + webWidget()->paint(skia::BeginPlatformPaint(canvas()), rect); + skia::EndPlatformPaint(canvas()); #else webWidget()->paint(canvas(), rect); #endif @@ -1512,13 +1513,14 @@ void WebViewHost::paintInvalidatedRegion() ASSERT(m_paintRect.isEmpty()); } -PlatformCanvas* WebViewHost::canvas() +SkCanvas* WebViewHost::canvas() { if (m_canvas) return m_canvas.get(); WebSize widgetSize = webWidget()->size(); resetScrollRect(); - m_canvas.set(new PlatformCanvas(widgetSize.width, widgetSize.height, true)); + m_canvas.set(skia::CreateBitmapCanvas( + widgetSize.width, widgetSize.height, true)); return m_canvas.get(); } diff --git a/Tools/DumpRenderTree/chromium/WebViewHost.h b/Tools/DumpRenderTree/chromium/WebViewHost.h index 014be2e..3251823 100644 --- a/Tools/DumpRenderTree/chromium/WebViewHost.h +++ b/Tools/DumpRenderTree/chromium/WebViewHost.h @@ -45,7 +45,9 @@ #include <wtf/text/WTFString.h> class LayoutTestController; +class SkCanvas; class TestShell; + namespace WebKit { class WebFrame; class WebDeviceOrientationClient; @@ -61,9 +63,6 @@ struct WebRect; struct WebURLError; struct WebWindowFeatures; } -namespace skia { -class PlatformCanvas; -} class WebViewHost : public WebKit::WebSpellCheckClient, public WebKit::WebViewClient, public WebKit::WebFrameClient, public NavigationHost { public: @@ -87,7 +86,7 @@ class WebViewHost : public WebKit::WebSpellCheckClient, public WebKit::WebViewCl void paintRect(const WebKit::WebRect&); void updatePaintRect(const WebKit::WebRect&); void paintInvalidatedRegion(); - skia::PlatformCanvas* canvas(); + SkCanvas* canvas(); void displayRepaintMask(); void loadURLForFrame(const WebKit::WebURL&, const WebKit::WebString& frameName); @@ -106,7 +105,7 @@ class WebViewHost : public WebKit::WebSpellCheckClient, public WebKit::WebViewCl virtual bool navigate(const TestNavigationEntry&, bool reload); // WebKit::WebSpellCheckClient - virtual void spellCheck(const WebKit::WebString&, int& offset, int& length); + virtual void spellCheck(const WebKit::WebString&, int& offset, int& length, WebKit::WebVector<WebKit::WebString>* optionalSuggestions); virtual void requestCheckingOfText(const WebKit::WebString&, WebKit::WebTextCheckingCompletion*); virtual WebKit::WebString autoCorrectWord(const WebKit::WebString&); @@ -193,7 +192,7 @@ class WebViewHost : public WebKit::WebSpellCheckClient, public WebKit::WebViewCl virtual void didFailProvisionalLoad(WebKit::WebFrame*, const WebKit::WebURLError&); virtual void didCommitProvisionalLoad(WebKit::WebFrame*, bool isNewNavigation); virtual void didClearWindowObject(WebKit::WebFrame*); - virtual void didReceiveTitle(WebKit::WebFrame*, const WebKit::WebString&); + virtual void didReceiveTitle(WebKit::WebFrame*, const WebKit::WebString&, WebKit::WebTextDirection); virtual void didFinishDocumentLoad(WebKit::WebFrame*); virtual void didHandleOnloadEvents(WebKit::WebFrame*); virtual void didFailLoad(WebKit::WebFrame*, const WebKit::WebURLError&); @@ -333,7 +332,7 @@ private: MockSpellCheck m_spellcheck; // Painting. - OwnPtr<skia::PlatformCanvas> m_canvas; + OwnPtr<SkCanvas> m_canvas; WebKit::WebRect m_paintRect; bool m_isPainting; diff --git a/Tools/DumpRenderTree/config.h b/Tools/DumpRenderTree/config.h index 90cfcf6..bde0cc8 100644 --- a/Tools/DumpRenderTree/config.h +++ b/Tools/DumpRenderTree/config.h @@ -48,8 +48,8 @@ #define WEBKIT_EXPORTDATA #endif -#define WTF_EXPORT_PRIVATE JS_EXPORTDATA -#define JS_EXPORT_PRIVATE JS_EXPORTDATA +#define WTF_EXPORT_PRIVATE +#define JS_EXPORT_PRIVATE #endif /* USE(EXPORT_MACROS) */ @@ -74,10 +74,10 @@ #if PLATFORM(WIN) #define WTF_USE_CF 1 #if defined(WIN_CAIRO) -#define WTF_PLATFORM_CAIRO 1 +#define WTF_USE_CAIRO 1 #define WTF_USE_CURL 1 #else -#define WTF_PLATFORM_CG 1 +#define WTF_USE_CG 1 #define WTF_USE_CFNETWORK 1 #endif diff --git a/Tools/DumpRenderTree/gtk/AccessibilityUIElementGtk.cpp b/Tools/DumpRenderTree/gtk/AccessibilityUIElementGtk.cpp index ff76e4b..8a4a490 100644 --- a/Tools/DumpRenderTree/gtk/AccessibilityUIElementGtk.cpp +++ b/Tools/DumpRenderTree/gtk/AccessibilityUIElementGtk.cpp @@ -26,15 +26,14 @@ #include "config.h" #include "AccessibilityUIElement.h" + #include "GOwnPtr.h" #include "GRefPtr.h" - +#include "WebCoreSupport/DumpRenderTreeSupportGtk.h" #include <JavaScriptCore/JSStringRef.h> -#include <wtf/Assertions.h> - #include <atk/atk.h> #include <gtk/gtk.h> - +#include <wtf/Assertions.h> AccessibilityUIElement::AccessibilityUIElement(PlatformUIElement element) : m_element(element) @@ -488,16 +487,56 @@ int AccessibilityUIElement::indexInTable() return 0; } +static JSStringRef indexRangeInTable(PlatformUIElement element, bool isRowRange) +{ + GOwnPtr<gchar> rangeString(g_strdup("{0, 0}")); + + if (!element) + return JSStringCreateWithUTF8CString(rangeString.get()); + + ASSERT(ATK_IS_OBJECT(element)); + + AtkObject* axTable = atk_object_get_parent(ATK_OBJECT(element)); + if (!axTable || !ATK_IS_TABLE(axTable)) + return JSStringCreateWithUTF8CString(rangeString.get()); + + // Look for the cell in the table. + gint indexInParent = atk_object_get_index_in_parent(ATK_OBJECT(element)); + if (indexInParent == -1) + return JSStringCreateWithUTF8CString(rangeString.get()); + + int row = -1; + int column = -1; + row = atk_table_get_row_at_index(ATK_TABLE(axTable), indexInParent); + column = atk_table_get_column_at_index(ATK_TABLE(axTable), indexInParent); + + // Get the actual values, if row and columns are valid values. + if (row != -1 && column != -1) { + int base = 0; + int length = 0; + if (isRowRange) { + base = row; + length = atk_table_get_row_extent_at(ATK_TABLE(axTable), row, column); + } else { + base = column; + length = atk_table_get_column_extent_at(ATK_TABLE(axTable), row, column); + } + rangeString.set(g_strdup_printf("{%d, %d}", base, length)); + } + + return JSStringCreateWithUTF8CString(rangeString.get()); +} + JSStringRef AccessibilityUIElement::rowIndexRange() { - // FIXME: implement - return JSStringCreateWithCharacters(0, 0); + // Range in table for rows. + return indexRangeInTable(m_element, true); } JSStringRef AccessibilityUIElement::columnIndexRange() { - // FIXME: implement - return JSStringCreateWithCharacters(0, 0); + // Range in table for columns. + return indexRangeInTable(m_element, false); } int AccessibilityUIElement::lineForIndex(int) @@ -532,8 +571,13 @@ bool AccessibilityUIElement::attributedStringRangeIsMisspelled(unsigned location AccessibilityUIElement AccessibilityUIElement::cellForColumnAndRow(unsigned column, unsigned row) { - // FIXME: implement - return 0; + if (!m_element) + return 0; + + ASSERT(ATK_IS_TABLE(m_element)); + + AtkObject* foundCell = atk_table_ref_at(ATK_TABLE(m_element), row, column); + return foundCell ? AccessibilityUIElement(foundCell) : 0; } JSStringRef AccessibilityUIElement::selectedTextRange() @@ -572,12 +616,20 @@ bool AccessibilityUIElement::isAttributeSupported(JSStringRef attribute) void AccessibilityUIElement::increment() { - // FIXME: implement + if (!m_element) + return; + + ASSERT(ATK_IS_OBJECT(m_element)); + DumpRenderTreeSupportGtk::incrementAccessibilityValue(ATK_OBJECT(m_element)); } void AccessibilityUIElement::decrement() { - // FIXME: implement + if (!m_element) + return; + + ASSERT(ATK_IS_OBJECT(m_element)); + DumpRenderTreeSupportGtk::decrementAccessibilityValue(ATK_OBJECT(m_element)); } void AccessibilityUIElement::press() diff --git a/Tools/DumpRenderTree/gtk/DumpRenderTree.cpp b/Tools/DumpRenderTree/gtk/DumpRenderTree.cpp index f768b43..a281e48 100644 --- a/Tools/DumpRenderTree/gtk/DumpRenderTree.cpp +++ b/Tools/DumpRenderTree/gtk/DumpRenderTree.cpp @@ -39,6 +39,7 @@ #include "GOwnPtr.h" #include "LayoutTestController.h" #include "PixelDumpSupport.h" +#include "PlainTextController.h" #include "TextInputController.h" #include "WebCoreSupport/DumpRenderTreeSupportGtk.h" #include "WorkQueue.h" @@ -814,6 +815,13 @@ static void webViewOnloadEvent(WebKitWebView* view, WebKitWebFrame* frame, void* } } +static void addControllerToWindow(JSContextRef context, JSObjectRef windowObject, const char* controllerName, JSValueRef controller) +{ + JSStringRef controllerNameStr = JSStringCreateWithUTF8CString(controllerName); + JSObjectSetProperty(context, windowObject, controllerNameStr, controller, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete, 0); + JSStringRelease(controllerNameStr); +} + static void webViewWindowObjectCleared(WebKitWebView* view, WebKitWebFrame* frame, JSGlobalContextRef context, JSObjectRef windowObject, gpointer data) { JSValueRef exception = 0; @@ -828,15 +836,9 @@ static void webViewWindowObjectCleared(WebKitWebView* view, WebKitWebFrame* fram axController->makeWindowObject(context, windowObject, &exception); ASSERT(!exception); - JSStringRef eventSenderStr = JSStringCreateWithUTF8CString("eventSender"); - JSValueRef eventSender = makeEventSender(context, !webkit_web_frame_get_parent(frame)); - JSObjectSetProperty(context, windowObject, eventSenderStr, eventSender, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete, 0); - JSStringRelease(eventSenderStr); - - JSStringRef textInputControllerStr = JSStringCreateWithUTF8CString("textInputController"); - JSValueRef textInputController = makeTextInputController(context); - JSObjectSetProperty(context, windowObject, textInputControllerStr, textInputController, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete, 0); - JSStringRelease(textInputControllerStr); + addControllerToWindow(context, windowObject, "eventSender", makeEventSender(context, !webkit_web_frame_get_parent(frame))); + addControllerToWindow(context, windowObject, "plainText", makePlainTextController(context)); + addControllerToWindow(context, windowObject, "textInputController", makeTextInputController(context)); } static gboolean webViewConsoleMessage(WebKitWebView* view, const gchar* message, unsigned int line, const gchar* sourceId, gpointer data) @@ -941,10 +943,8 @@ static void webViewStatusBarTextChanged(WebKitWebView* view, const gchar* messag { // Are we doing anything wrong? One test that does not call // dumpStatusCallbacks gets true here - if (gLayoutTestController->dumpStatusCallbacks()) { - if (message && strcmp(message, "")) - printf("UI DELEGATE STATUS CALLBACK: setStatusText:%s\n", message); - } + if (gLayoutTestController->dumpStatusCallbacks()) + printf("UI DELEGATE STATUS CALLBACK: setStatusText:%s\n", message); } static gboolean webViewClose(WebKitWebView* view) @@ -1048,6 +1048,9 @@ static void frameCreatedCallback(WebKitWebView* webView, WebKitWebFrame* webFram static void willSendRequestCallback(WebKitWebView* webView, WebKitWebFrame*, WebKitWebResource*, WebKitNetworkRequest* request, WebKitNetworkResponse*) { + if (!done && gLayoutTestController->willSendRequestReturnsNull()) + return; + SoupMessage* soupMessage = webkit_network_request_get_message(request); SoupURI* uri = soup_uri_new(webkit_network_request_get_uri(request)); @@ -1058,8 +1061,8 @@ static void willSendRequestCallback(WebKitWebView* webView, WebKitWebFrame*, Web soup_uri_free(uri); return; } - soup_uri_free(uri); - + if (uri) + soup_uri_free(uri); if (soupMessage) { const set<string>& clearHeaders = gLayoutTestController->willSendRequestClearHeaders(); diff --git a/Tools/DumpRenderTree/gtk/LayoutTestControllerGtk.cpp b/Tools/DumpRenderTree/gtk/LayoutTestControllerGtk.cpp index c26e2db..29742be 100644 --- a/Tools/DumpRenderTree/gtk/LayoutTestControllerGtk.cpp +++ b/Tools/DumpRenderTree/gtk/LayoutTestControllerGtk.cpp @@ -778,6 +778,8 @@ void LayoutTestController::overridePreference(JSStringRef key, JSStringRef value propertyName = "enable-plugins"; else if (g_str_equal(originalName.get(), "WebKitHyperlinkAuditingEnabled")) propertyName = "enable-hyperlink-auditing"; + else if (g_str_equal(originalName.get(), "WebKitWebGLEnabled")) + propertyName = "enable-webgl"; else if (g_str_equal(originalName.get(), "WebKitTabToLinksPreferenceKey")) { DumpRenderTreeSupportGtk::setLinksIncludedInFocusChain(!g_ascii_strcasecmp(valueAsString.get(), "true") || !g_ascii_strcasecmp(valueAsString.get(), "1")); return; @@ -917,6 +919,11 @@ void LayoutTestController::setEditingBehavior(const char* editingBehavior) g_object_set(G_OBJECT(settings), "editing-behavior", WEBKIT_EDITING_BEHAVIOR_UNIX, NULL); } +JSValueRef LayoutTestController::shadowRoot(JSContextRef context, JSValueRef element) +{ + return DumpRenderTreeSupportGtk::shadowRoot(context, element); +} + void LayoutTestController::abortModal() { } diff --git a/Tools/DumpRenderTree/gtk/PixelDumpSupportGtk.cpp b/Tools/DumpRenderTree/gtk/PixelDumpSupportGtk.cpp index 1e591bb..2bd8fe2 100644 --- a/Tools/DumpRenderTree/gtk/PixelDumpSupportGtk.cpp +++ b/Tools/DumpRenderTree/gtk/PixelDumpSupportGtk.cpp @@ -32,9 +32,10 @@ #include "DumpRenderTree.h" #include "GtkVersioning.h" #include "PixelDumpSupportCairo.h" +#include "WebCoreSupport/DumpRenderTreeSupportGtk.h" #include <webkit/webkit.h> -PassRefPtr<BitmapContext> createBitmapContextFromWebView(bool, bool, bool, bool) +PassRefPtr<BitmapContext> createBitmapContextFromWebView(bool, bool, bool, bool drawSelectionRect) { WebKitWebView* view = webkit_web_frame_get_web_view(mainFrame); GtkWidget* viewContainer = gtk_widget_get_parent(GTK_WIDGET(view)); @@ -49,6 +50,7 @@ PassRefPtr<BitmapContext> createBitmapContextFromWebView(bool, bool, bool, bool) cairo_surface_t* imageSurface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, width, height); cairo_t* context = cairo_create(imageSurface); + #ifdef GTK_API_VERSION_2 gdk_cairo_set_source_pixmap(context, pixmap, 0, 0); cairo_paint(context); @@ -57,5 +59,15 @@ PassRefPtr<BitmapContext> createBitmapContextFromWebView(bool, bool, bool, bool) gtk_widget_draw(viewContainer, context); #endif + if (drawSelectionRect) { + GdkRectangle rectangle; + DumpRenderTreeSupportGtk::rectangleForSelection(mainFrame, &rectangle); + + cairo_set_line_width(context, 1.0); + cairo_rectangle(context, rectangle.x, rectangle.y, rectangle.width, rectangle.height); + cairo_set_source_rgba(context, 1.0, 0.0, 0.0, 1.0); + cairo_stroke(context); + } + return BitmapContext::createByAdoptingBitmapAndContext(0, context); } diff --git a/Tools/DumpRenderTree/gtk/PlainTextController.cpp b/Tools/DumpRenderTree/gtk/PlainTextController.cpp new file mode 100644 index 0000000..25e251a --- /dev/null +++ b/Tools/DumpRenderTree/gtk/PlainTextController.cpp @@ -0,0 +1,65 @@ +/* + * Copyright (C) 2011 Igalia S.L. + * + * 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. + */ + +#include "config.h" +#include "PlainTextController.h" + +#include "DumpRenderTree.h" +#include "WebCoreSupport/DumpRenderTreeSupportGtk.h" +#include <GOwnPtrGtk.h> +#include <JavaScriptCore/JSObjectRef.h> +#include <JavaScriptCore/JSRetainPtr.h> +#include <JavaScriptCore/JSStringRef.h> +#include <webkit/webkit.h> + +static JSValueRef plainTextCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + g_return_val_if_fail(argumentCount == 1, JSValueMakeUndefined(context)); + WebKitDOMRange* kitRange = DumpRenderTreeSupportGtk::jsValueToDOMRange(context, arguments[0]); + g_return_val_if_fail(kitRange, JSValueMakeUndefined(context)); + + GOwnPtr<gchar> text(webkit_dom_range_get_text(kitRange)); + JSRetainPtr<JSStringRef> jsText(Adopt, JSStringCreateWithUTF8CString(text.get())); + return JSValueMakeString(context, jsText.get()); +} + +JSObjectRef makePlainTextController(JSContextRef context) +{ + static JSStaticFunction staticFunctions[] = { + { "plainText", plainTextCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { 0, 0, 0 } + }; + + static JSClassRef plainTextControllerClass = 0; + if (!plainTextControllerClass) { + JSClassDefinition classDefinition = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; + classDefinition.staticFunctions = staticFunctions; + plainTextControllerClass = JSClassCreate(&classDefinition); + } + return JSObjectMake(context, plainTextControllerClass, 0); +} diff --git a/Tools/DumpRenderTree/gtk/PlainTextController.h b/Tools/DumpRenderTree/gtk/PlainTextController.h new file mode 100644 index 0000000..dadfc13 --- /dev/null +++ b/Tools/DumpRenderTree/gtk/PlainTextController.h @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2011 Igalia S.L. + * + * 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. + */ + +#ifndef PlainTextController_h +#define PlainTextController_h + +typedef const struct OpaqueJSContext* JSContextRef; +typedef struct OpaqueJSValue* JSObjectRef; + +JSObjectRef makePlainTextController(JSContextRef); + +#endif diff --git a/Tools/DumpRenderTree/gtk/TextInputController.cpp b/Tools/DumpRenderTree/gtk/TextInputController.cpp index 7243fdc..d1aa33d 100644 --- a/Tools/DumpRenderTree/gtk/TextInputController.cpp +++ b/Tools/DumpRenderTree/gtk/TextInputController.cpp @@ -36,6 +36,7 @@ #include <JavaScriptCore/JSRetainPtr.h> #include <JavaScriptCore/JSStringRef.h> #include <cstring> +#include <webkit/webkit.h> static JSValueRef setMarkedTextCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) { diff --git a/Tools/DumpRenderTree/mac/DumpRenderTree.mm b/Tools/DumpRenderTree/mac/DumpRenderTree.mm index 207e8fb..441f6bb 100644 --- a/Tools/DumpRenderTree/mac/DumpRenderTree.mm +++ b/Tools/DumpRenderTree/mac/DumpRenderTree.mm @@ -455,6 +455,7 @@ static void resetDefaultsToConsistentValues() [preferences setOfflineWebApplicationCacheEnabled:YES]; [preferences setDeveloperExtrasEnabled:NO]; [preferences setLoadsImagesAutomatically:YES]; + [preferences setLoadsSiteIconsIgnoringImageLoadingPreference:NO]; [preferences setFrameFlatteningEnabled:NO]; [preferences setSpatialNavigationEnabled:NO]; [preferences setEditingBehavior:WebKitEditingMacBehavior]; @@ -468,6 +469,10 @@ static void resetDefaultsToConsistentValues() // So, turn it off for now, but we might want to turn it back on some day. [preferences setUsesPageCache:NO]; [preferences setAcceleratedCompositingEnabled:YES]; +#if USE(CA) && !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) && !defined(BUILDING_ON_SNOW_LEOPARD) + [preferences setCanvasUsesAcceleratedDrawing:YES]; + [preferences setAcceleratedDrawingEnabled:NO]; +#endif [preferences setWebGLEnabled:NO]; [preferences setUsePreHTML5ParserQuirks:NO]; [preferences setAsynchronousSpellCheckingEnabled:NO]; @@ -730,6 +735,14 @@ static NSInteger compareHistoryItems(id item1, id item2, void *context) return [[item1 target] caseInsensitiveCompare:[item2 target]]; } +static NSData *dumpAudio() +{ + const char *encodedAudioData = gLayoutTestController->encodedAudioData().c_str(); + + NSData *data = [NSData dataWithBytes:encodedAudioData length:gLayoutTestController->encodedAudioData().length()]; + return data; +} + static void dumpHistoryItem(WebHistoryItem *item, int indent, BOOL current) { int start = 0; @@ -933,7 +946,10 @@ void dump() gLayoutTestController->setDumpAsText(true); gLayoutTestController->setGeneratePixelResults(false); } - if (gLayoutTestController->dumpAsText()) { + if (gLayoutTestController->dumpAsAudio()) { + resultData = dumpAudio(); + resultMimeType = @"audio/wav"; + } else if (gLayoutTestController->dumpAsText()) { resultString = dumpFramesAsText(mainFrame); } else if (gLayoutTestController->dumpAsPDF()) { resultData = dumpFrameAsPDF(mainFrame); @@ -956,6 +972,9 @@ void dump() printf("Content-Type: %s\n", [resultMimeType UTF8String]); + if (gLayoutTestController->dumpAsAudio()) + printf("Content-Transfer-Encoding: base64\n"); + if (resultData) { fwrite([resultData bytes], 1, [resultData length], stdout); @@ -1022,6 +1041,7 @@ static void resetWebViewToConsistentStateBeforeTesting() [(EditingDelegate *)[webView editingDelegate] setAcceptsEditing:YES]; [webView makeTextStandardSize:nil]; [webView resetPageZoom:nil]; + [webView _scaleWebView:1.0 atOrigin:NSZeroPoint]; [webView setTabKeyCyclesThroughElements:YES]; [webView setPolicyDelegate:nil]; [policyDelegate setPermissive:NO]; diff --git a/Tools/DumpRenderTree/mac/EventSendingController.mm b/Tools/DumpRenderTree/mac/EventSendingController.mm index 9031c63..4497105 100644 --- a/Tools/DumpRenderTree/mac/EventSendingController.mm +++ b/Tools/DumpRenderTree/mac/EventSendingController.mm @@ -135,6 +135,7 @@ BOOL replayingSavedEvents; || aSelector == @selector(textZoomOut) || aSelector == @selector(zoomPageIn) || aSelector == @selector(zoomPageOut) + || aSelector == @selector(scalePageBy:atX:andY:) || aSelector == @selector(mouseScrollByX:andY:) || aSelector == @selector(continuousMouseScrollByX:andY:)) return NO; @@ -174,6 +175,8 @@ BOOL replayingSavedEvents; return @"mouseScrollBy"; if (aSelector == @selector(continuousMouseScrollByX:andY:)) return @"continuousMouseScrollBy"; + if (aSelector == @selector(scalePageBy:atX:andY:)) + return @"scalePageBy"; return nil; } @@ -361,6 +364,11 @@ static int buildModifierFlags(const WebScriptObject* modifiers) [[mainFrame webView] zoomPageOut:self]; } +- (void)scalePageBy:(float)scale atX:(float)x andY:(float)y +{ + [[mainFrame webView] _scaleWebView:scale atOrigin:NSMakePoint(x, y)]; +} + - (void)mouseUp:(int)buttonNumber withModifiers:(WebScriptObject*)modifiers { if (dragMode && !replayingSavedEvents) { diff --git a/Tools/DumpRenderTree/mac/LayoutTestControllerMac.mm b/Tools/DumpRenderTree/mac/LayoutTestControllerMac.mm index 66c0cce..4ebf271 100644 --- a/Tools/DumpRenderTree/mac/LayoutTestControllerMac.mm +++ b/Tools/DumpRenderTree/mac/LayoutTestControllerMac.mm @@ -1068,6 +1068,14 @@ void LayoutTestController::setEditingBehavior(const char* editingBehavior) [editingBehaviorNS release]; } +JSValueRef LayoutTestController::shadowRoot(JSContextRef context, JSValueRef jsElement) +{ + DOMElement *element = [DOMElement _DOMElementFromJSContext:context value:jsElement]; + if (!element) + return JSValueMakeNull(context); + return [element _shadowRoot:context]; +} + void LayoutTestController::abortModal() { [NSApp abortModal]; diff --git a/Tools/DumpRenderTree/qt/DumpRenderTree.pro b/Tools/DumpRenderTree/qt/DumpRenderTree.pro index a76b886..242651d 100644 --- a/Tools/DumpRenderTree/qt/DumpRenderTree.pro +++ b/Tools/DumpRenderTree/qt/DumpRenderTree.pro @@ -1,6 +1,6 @@ TARGET = DumpRenderTree CONFIG -= app_bundle -CONFIG += uitools +!isEqual(QT_ARCH,sh4): CONFIG += uitools BASEDIR = $$PWD/../ isEmpty(OUTPUT_DIR): OUTPUT_DIR = ../../.. @@ -13,7 +13,7 @@ INCLUDEPATH += ../../../Source/WebKit/qt/WebCoreSupport INCLUDEPATH += $$BASEDIR DESTDIR = ../../bin -unix:!mac:!symbian { +unix:!mac:!symbian:!embedded { CONFIG += link_pkgconfig PKGCONFIG += fontconfig } diff --git a/Tools/DumpRenderTree/qt/DumpRenderTreeQt.cpp b/Tools/DumpRenderTree/qt/DumpRenderTreeQt.cpp index 97d9f20..1a6c833 100644 --- a/Tools/DumpRenderTree/qt/DumpRenderTreeQt.cpp +++ b/Tools/DumpRenderTree/qt/DumpRenderTreeQt.cpp @@ -190,6 +190,7 @@ void WebPage::resetSettings() settings()->resetAttribute(QWebSettings::LinksIncludedInFocusChain); settings()->resetAttribute(QWebSettings::OfflineWebApplicationCacheEnabled); settings()->resetAttribute(QWebSettings::LocalContentCanAccessRemoteUrls); + settings()->resetAttribute(QWebSettings::LocalContentCanAccessFileUrls); settings()->resetAttribute(QWebSettings::PluginsEnabled); settings()->resetAttribute(QWebSettings::JavascriptCanAccessClipboard); settings()->resetAttribute(QWebSettings::AutoLoadImages); @@ -997,6 +998,8 @@ void DumpRenderTree::dump() } if (dumpImage) { + image.setText("checksum", actualHash); + QBuffer buffer; buffer.open(QBuffer::WriteOnly); image.save(&buffer, "PNG"); @@ -1136,6 +1139,17 @@ void DumpRenderTree::switchFocus(bool focused) } +QList<WebPage*> DumpRenderTree::getAllPages() const +{ + QList<WebPage*> pages; + pages.append(m_page); + foreach (QObject* widget, windows) { + if (WebPage* page = widget->findChild<WebPage*>()) + pages.append(page); + } + return pages; +} + #if defined(Q_WS_X11) void DumpRenderTree::initializeFonts() { diff --git a/Tools/DumpRenderTree/qt/DumpRenderTreeQt.h b/Tools/DumpRenderTree/qt/DumpRenderTreeQt.h index 858856f..cb66296 100644 --- a/Tools/DumpRenderTree/qt/DumpRenderTreeQt.h +++ b/Tools/DumpRenderTree/qt/DumpRenderTreeQt.h @@ -100,6 +100,7 @@ public: void switchFocus(bool focused); WebPage *webPage() const { return m_page; } + QList<WebPage*> getAllPages() const; #if defined(Q_WS_X11) static void initializeFonts(); diff --git a/Tools/DumpRenderTree/qt/LayoutTestControllerQt.cpp b/Tools/DumpRenderTree/qt/LayoutTestControllerQt.cpp index 4e3087e..d9f1a74 100644 --- a/Tools/DumpRenderTree/qt/LayoutTestControllerQt.cpp +++ b/Tools/DumpRenderTree/qt/LayoutTestControllerQt.cpp @@ -780,10 +780,19 @@ void LayoutTestController::setGeolocationPermission(bool allow) DumpRenderTreeSupportQt::setMockGeolocationPermission(m_drt->webPage(), allow); } +QVariant LayoutTestController::shadowRoot(const QWebElement& element) +{ + return DumpRenderTreeSupportQt::shadowRoot(element); +} + int LayoutTestController::numberOfPendingGeolocationPermissionRequests() { - // FIXME: Implement for Geolocation layout tests. - return -1; + int pendingPermissionCount = 0; + QList<WebCore::WebPage*> pages = m_drt->getAllPages(); + foreach (WebCore::WebPage* page, pages) + pendingPermissionCount += DumpRenderTreeSupportQt::numberOfPendingGeolocationPermissionRequests(page); + + return pendingPermissionCount; } void LayoutTestController::setGeolocationPermissionCommon(bool allow) diff --git a/Tools/DumpRenderTree/qt/LayoutTestControllerQt.h b/Tools/DumpRenderTree/qt/LayoutTestControllerQt.h index f29233a..2c33401 100644 --- a/Tools/DumpRenderTree/qt/LayoutTestControllerQt.h +++ b/Tools/DumpRenderTree/qt/LayoutTestControllerQt.h @@ -197,7 +197,7 @@ public slots: void clearAllDatabases(); void setIconDatabaseEnabled(bool enable); - void setCustomPolicyDelegate(bool enabled, bool permissive = true); + void setCustomPolicyDelegate(bool enabled, bool permissive = false); void waitForPolicyDelegate(); void overridePreference(const QString& name, const QVariant& value); @@ -249,6 +249,8 @@ public slots: void setEditingBehavior(const QString& editingBehavior); + QVariant shadowRoot(const QWebElement&); + void evaluateScriptInIsolatedWorld(int worldID, const QString& script); bool isPageBoxVisible(int pageIndex); QString pageSizeAndMarginsInPixels(int pageIndex, int width, int height, int marginTop, int marginRight, int marginBottom, int marginLeft); diff --git a/Tools/DumpRenderTree/qt/TestNetscapePlugin/TestNetscapePlugin.pro b/Tools/DumpRenderTree/qt/TestNetscapePlugin/TestNetscapePlugin.pro index 6741668..e03c876 100644 --- a/Tools/DumpRenderTree/qt/TestNetscapePlugin/TestNetscapePlugin.pro +++ b/Tools/DumpRenderTree/qt/TestNetscapePlugin/TestNetscapePlugin.pro @@ -33,6 +33,7 @@ SOURCES = PluginObject.cpp \ Tests/GetURLWithJavaScriptURLDestroyingPlugin.cpp \ Tests/GetUserAgentWithNullNPPFromNPPNew.cpp \ Tests/NPDeallocateCalledBeforeNPShutdown.cpp \ + Tests/NPPSetWindowCalledDuringDestruction.cpp \ Tests/NPRuntimeObjectFromDestroyedPlugin.cpp \ Tests/NPRuntimeRemoveProperty.cpp \ Tests/NullNPPGetValuePointer.cpp \ diff --git a/Tools/DumpRenderTree/qt/main.cpp b/Tools/DumpRenderTree/qt/main.cpp index bc762e5..89a5128 100644 --- a/Tools/DumpRenderTree/qt/main.cpp +++ b/Tools/DumpRenderTree/qt/main.cpp @@ -54,7 +54,7 @@ #include <limits.h> #include <signal.h> -#if defined(__GLIBC__) +#if defined(__GLIBC__) && !defined(__UCLIBC__) #include <execinfo.h> #endif @@ -97,7 +97,7 @@ void printUsage() QString get_backtrace() { QString s; -#if defined(__GLIBC__) +#if defined(__GLIBC__) && !defined(__UCLIBC__) void* array[256]; size_t size; /* number of stack frames */ diff --git a/Tools/DumpRenderTree/win/DumpRenderTree.cpp b/Tools/DumpRenderTree/win/DumpRenderTree.cpp index 66e7311..2db43da 100644 --- a/Tools/DumpRenderTree/win/DumpRenderTree.cpp +++ b/Tools/DumpRenderTree/win/DumpRenderTree.cpp @@ -168,12 +168,15 @@ wstring urlSuitableForTestResult(const wstring& urlString) return cfStringRefToWString(substringFromIndex(path.get(), CFStringGetLength(basePath.get())).get()); } -wstring lastPathComponent(const wstring& url) +wstring lastPathComponent(const wstring& urlString) { - if (url.empty()) - return url; + if (urlString.empty()) + return urlString; + + RetainPtr<CFURLRef> url(AdoptCF, CFURLCreateWithBytes(kCFAllocatorDefault, reinterpret_cast<const UInt8*>(urlString.c_str()), urlString.length() * sizeof(wstring::value_type), kCFStringEncodingUTF16, 0)); + RetainPtr<CFStringRef> lastPathComponent(CFURLCopyLastPathComponent(url.get())); - return PathFindFileNameW(url.c_str()); + return cfStringRefToWString(lastPathComponent.get()); } static string toUTF8(const wchar_t* wideString, size_t length) @@ -873,6 +876,7 @@ static void resetDefaultsToConsistentValues(IWebPreferences* preferences) prefsPrivate->setXSSAuditorEnabled(FALSE); prefsPrivate->setFrameFlatteningEnabled(FALSE); prefsPrivate->setOfflineWebApplicationCacheEnabled(TRUE); + prefsPrivate->setLoadsSiteIconsIgnoringImageLoadingPreference(FALSE); } setAlwaysAcceptCookies(false); diff --git a/Tools/DumpRenderTree/win/DumpRenderTree.vcproj b/Tools/DumpRenderTree/win/DumpRenderTree.vcproj index 39d2df2..803917a 100644 --- a/Tools/DumpRenderTree/win/DumpRenderTree.vcproj +++ b/Tools/DumpRenderTree/win/DumpRenderTree.vcproj @@ -515,6 +515,14 @@ > </File> <File + RelativePath="..\CyclicRedundancyCheck.cpp" + > + </File> + <File + RelativePath="..\CyclicRedundancyCheck.h" + > + </File> + <File RelativePath=".\DraggingInfo.h" > </File> diff --git a/Tools/DumpRenderTree/win/DumpRenderTreeProduction.vsprops b/Tools/DumpRenderTree/win/DumpRenderTreeProduction.vsprops index 818bff2..df20c64 100644 --- a/Tools/DumpRenderTree/win/DumpRenderTreeProduction.vsprops +++ b/Tools/DumpRenderTree/win/DumpRenderTreeProduction.vsprops @@ -6,7 +6,7 @@ InheritedPropertySheets=" $(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\FeatureDefines.vsprops; $(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\common.vsprops; - $(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\release.vsprops; + $(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\releaseproduction.vsprops; $(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\production.vsprops; .\DumpRenderTreeCommon.vsprops; .\DumpRenderTreeApple.vsprops" diff --git a/Tools/DumpRenderTree/win/DumpRenderTreeRelease.vsprops b/Tools/DumpRenderTree/win/DumpRenderTreeRelease.vsprops index c39a9cd..5f12a6b 100644 --- a/Tools/DumpRenderTree/win/DumpRenderTreeRelease.vsprops +++ b/Tools/DumpRenderTree/win/DumpRenderTreeRelease.vsprops @@ -6,6 +6,7 @@ InheritedPropertySheets=" $(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\FeatureDefines.vsprops; $(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\common.vsprops; + $(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\releaseproduction.vsprops; $(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\release.vsprops; .\DumpRenderTreeCommon.vsprops; .\DumpRenderTreeApple.vsprops" diff --git a/Tools/DumpRenderTree/win/DumpRenderTreeReleaseCairoCFLite.vsprops b/Tools/DumpRenderTree/win/DumpRenderTreeReleaseCairoCFLite.vsprops index 508e8c5..27fefbb 100644 --- a/Tools/DumpRenderTree/win/DumpRenderTreeReleaseCairoCFLite.vsprops +++ b/Tools/DumpRenderTree/win/DumpRenderTreeReleaseCairoCFLite.vsprops @@ -6,6 +6,7 @@ InheritedPropertySheets=" $(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\FeatureDefinesCairo.vsprops; $(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\common.vsprops; + $(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\releaseproduction.vsprops; $(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\release.vsprops; $(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\WinCairo.vsprops; $(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\cURL.vsprops; diff --git a/Tools/DumpRenderTree/win/ImageDiff.vcproj b/Tools/DumpRenderTree/win/ImageDiff.vcproj index 7094fec..66d4b65 100644 --- a/Tools/DumpRenderTree/win/ImageDiff.vcproj +++ b/Tools/DumpRenderTree/win/ImageDiff.vcproj @@ -199,6 +199,7 @@ </Configuration> <Configuration Name="Debug_Cairo_CFLite|Win32" + IntermediateDirectory="$(ConfigurationName)" ConfigurationType="1" InheritedPropertySheets=".\ImageDiffDebugCairoCFLite.vsprops" CharacterSet="2" @@ -386,8 +387,60 @@ </References> <Files> <File + RelativePath="..\win\ImageDiffCairo.cpp" + > + <FileConfiguration + Name="Debug|Win32" + ExcludedFromBuild="true" + > + <Tool + Name="VCCLCompilerTool" + /> + </FileConfiguration> + <FileConfiguration + Name="Release|Win32" + ExcludedFromBuild="true" + > + <Tool + Name="VCCLCompilerTool" + /> + </FileConfiguration> + <FileConfiguration + Name="Debug_All|Win32" + ExcludedFromBuild="true" + > + <Tool + Name="VCCLCompilerTool" + /> + </FileConfiguration> + <FileConfiguration + Name="Production|Win32" + ExcludedFromBuild="true" + > + <Tool + Name="VCCLCompilerTool" + /> + </FileConfiguration> + </File> + <File RelativePath="..\cg\ImageDiffCG.cpp" > + <FileConfiguration + Name="Debug_Cairo_CFLite|Win32" + ExcludedFromBuild="true" + > + <Tool + Name="VCCLCompilerTool" + /> + </FileConfiguration> + <FileConfiguration + Name="Release_Cairo_CFLite|Win32" + ExcludedFromBuild="true" + > + <Tool + Name="VCCLCompilerTool" + /> + </FileConfiguration> </File> </Files> <Globals> diff --git a/Tools/DumpRenderTree/win/ImageDiffCairo.cpp b/Tools/DumpRenderTree/win/ImageDiffCairo.cpp new file mode 100644 index 0000000..d10cc14 --- /dev/null +++ b/Tools/DumpRenderTree/win/ImageDiffCairo.cpp @@ -0,0 +1,260 @@ +/* + * Copyright (C) 2005, 2007 Apple Inc. All rights reserved. + * Copyright (C) 2005 Ben La Monica <ben.lamonica@gmail.com>. All rights reserved. + * Copyright (C) 2011 Brent Fulgham. 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR OR + * 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. + */ + +// FIXME: We need to be able to include these defines from a config.h somewhere. +#define JS_EXPORT_PRIVATE +#define WTF_EXPORT_PRIVATE + +#include <cairo.h> +#include <stdio.h> +#include <wtf/Platform.h> +#include <wtf/RefPtr.h> +#include <wtf/RetainPtr.h> + +#if PLATFORM(WIN) +#include <fcntl.h> +#include <io.h> +#include <windows.h> +#include <wtf/MathExtras.h> +#endif + +using namespace std; + +static const int s_bufferSize = 2048; +static const int s_bytesPerPixel = 4; +static cairo_user_data_key_t s_imageDataKey; + + +#if PLATFORM(WIN) +#undef min +#undef max + +static inline float strtof(const char* inputString, char** endptr) +{ + return strtod(inputString, endptr); +} +#endif + +static cairo_status_t readFromData(void* closure, unsigned char* data, unsigned int length) +{ + CFMutableDataRef dataSource = reinterpret_cast<CFMutableDataRef>(closure); + + CFRange range = CFRangeMake(0, length); + CFDataGetBytes(dataSource, range, data); + CFDataDeleteBytes(dataSource, range); + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_surface_t* createImageFromStdin(int bytesRemaining) +{ + unsigned char buffer[s_bufferSize]; + RetainPtr<CFMutableDataRef> data(AdoptCF, CFDataCreateMutable(0, bytesRemaining)); + + while (bytesRemaining > 0) { + size_t bytesToRead = min(bytesRemaining, s_bufferSize); + size_t bytesRead = fread(buffer, 1, bytesToRead, stdin); + CFDataAppendBytes(data.get(), buffer, static_cast<CFIndex>(bytesRead)); + bytesRemaining -= static_cast<int>(bytesRead); + } + + return cairo_image_surface_create_from_png_stream (static_cast<cairo_read_func_t>(readFromData), data.get()); +} + +static void releaseMallocBuffer(void* data) +{ + free(data); +} + +static inline float pixelDifference(float expected, float actual) +{ + return (actual - expected) / max<float>(255 - expected, expected); +} + +static inline void normalizeBuffer(float maxDistance, unsigned char* buffer, size_t length) +{ + if (maxDistance >= 1) + return; + + for (size_t p = 0; p < length; ++p) + buffer[p] /= maxDistance; +} + +static cairo_surface_t* createDifferenceImage(cairo_surface_t* baselineImage, cairo_surface_t* actualImage, float& difference) +{ + size_t width = cairo_image_surface_get_width(baselineImage); + size_t height = cairo_image_surface_get_height(baselineImage); + + unsigned char* baselinePixel = cairo_image_surface_get_data(baselineImage); + unsigned char* actualPixel = cairo_image_surface_get_data(actualImage); + + // Compare the content of the 2 bitmaps + void* diffBuffer = malloc(width * height); + unsigned char* diffPixel = reinterpret_cast<unsigned char*>(diffBuffer); + + float count = 0; + float sum = 0; + float maxDistance = 0; + for (size_t y = 0; y < height; ++y) { + for (size_t x = 0; x < width; ++x) { + float red = pixelDifference(baselinePixel[0], actualPixel[0]); + float green = pixelDifference(baselinePixel[1], actualPixel[1]); + float blue = pixelDifference(baselinePixel[2], actualPixel[2]); + float alpha = pixelDifference(baselinePixel[3], actualPixel[3]); + + float distance = sqrtf(red * red + green * green + blue * blue + alpha * alpha) / 2.0; + + *diffPixel++ = static_cast<unsigned char>(distance * 255); + + if (distance >= 1.0 / 255.0) { + ++count; + sum += distance; + if (distance > maxDistance) + maxDistance = distance; + } + + baselinePixel += s_bytesPerPixel; + actualPixel += s_bytesPerPixel; + } + } + + // Compute the difference as a percentage combining both the number of different pixels and their difference amount i.e. the average distance over the entire image + if (count > 0) + difference = 100.0f * sum / (height * width); + else + difference = 0; + + if (!difference) { + free(diffBuffer); + return 0; + } + + // Generate a normalized diff image + normalizeBuffer(maxDistance, reinterpret_cast<unsigned char*>(diffBuffer), height * width); + + cairo_surface_t* diffImage = cairo_image_surface_create_for_data(diffPixel, CAIRO_FORMAT_ARGB32, width, height, width * s_bytesPerPixel); + cairo_surface_set_user_data(diffImage, &s_imageDataKey, diffBuffer, releaseMallocBuffer); + + return diffImage; +} + +static inline bool imageHasAlpha(cairo_surface_t* image) +{ + return (cairo_image_surface_get_format(image) == CAIRO_FORMAT_ARGB32); +} + +static cairo_status_t writeToData(void* closure, unsigned char* data, unsigned int length) +{ + CFMutableDataRef dataTarget = reinterpret_cast<CFMutableDataRef>(closure); + + CFDataAppendBytes(dataTarget, data, length); + + return CAIRO_STATUS_SUCCESS; +} + +int main(int argc, const char* argv[]) +{ +#if PLATFORM(WIN) + _setmode(0, _O_BINARY); + _setmode(1, _O_BINARY); +#endif + + float tolerance = 0; + + for (int i = 1; i < argc; ++i) { + if (!strcmp(argv[i], "-t") || !strcmp(argv[i], "--tolerance")) { + if (i >= argc - 1) + exit(1); + tolerance = strtof(argv[i + 1], 0); + ++i; + continue; + } + } + + char buffer[s_bufferSize]; + cairo_surface_t* actualImage = 0; + cairo_surface_t* baselineImage = 0; + + while (fgets(buffer, sizeof(buffer), stdin)) { + char* newLineCharacter = strchr(buffer, '\n'); + if (newLineCharacter) + *newLineCharacter = '\0'; + + if (!strncmp("Content-Length: ", buffer, 16)) { + strtok(buffer, " "); + int imageSize = strtol(strtok(0, " "), 0, 10); + + if (imageSize > 0 && !actualImage) + actualImage = createImageFromStdin(imageSize); + else if (imageSize > 0 && !baselineImage) + baselineImage = createImageFromStdin(imageSize); + else + fputs("error, image size must be specified.\n", stdout); + } + + if (actualImage && baselineImage) { + cairo_surface_t* diffImage = 0; + float difference = 100.0; + + if ((cairo_image_surface_get_width(actualImage) == cairo_image_surface_get_width(baselineImage)) + && (cairo_image_surface_get_height(actualImage) == cairo_image_surface_get_height(baselineImage)) + && (imageHasAlpha(actualImage) == imageHasAlpha(baselineImage))) { + diffImage = createDifferenceImage(actualImage, baselineImage, difference); // difference is passed by reference + if (difference <= tolerance) + difference = 0; + else { + difference = roundf(difference * 100.0) / 100.0; + difference = max<float>(difference, 0.01); // round to 2 decimal places + } + } else + fputs("error, test and reference image have different properties.\n", stderr); + + if (difference > 0.0) { + if (diffImage) { + RetainPtr<CFMutableDataRef> imageData(AdoptCF, CFDataCreateMutable(0, 0)); + cairo_surface_write_to_png_stream(diffImage, (cairo_write_func_t)writeToData, imageData.get()); + printf("Content-Length: %lu\n", CFDataGetLength(imageData.get())); + fwrite(CFDataGetBytePtr(imageData.get()), 1, CFDataGetLength(imageData.get()), stdout); + cairo_surface_destroy(diffImage); + diffImage = 0; + } + + fprintf(stdout, "diff: %01.2f%% failed\n", difference); + } else + fprintf(stdout, "diff: %01.2f%% passed\n", difference); + + cairo_surface_destroy(actualImage); + cairo_surface_destroy(baselineImage); + actualImage = 0; + baselineImage = 0; + } + + fflush(stdout); + } + + return 0; +} diff --git a/Tools/DumpRenderTree/win/ImageDiffDebugCairoCFLite.vsprops b/Tools/DumpRenderTree/win/ImageDiffDebugCairoCFLite.vsprops index bd6bc8a..0205f9a 100644 --- a/Tools/DumpRenderTree/win/ImageDiffDebugCairoCFLite.vsprops +++ b/Tools/DumpRenderTree/win/ImageDiffDebugCairoCFLite.vsprops @@ -7,6 +7,6 @@ $(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\common.vsprops; $(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\debug.vsprops; $(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\debug_wincairo.vsprops; - .\ImageDiffCommon.vsprops" + .\ImageDiffWinCairoCommon.vsprops" > </VisualStudioPropertySheet> diff --git a/Tools/DumpRenderTree/win/ImageDiffProduction.vsprops b/Tools/DumpRenderTree/win/ImageDiffProduction.vsprops index 37ff9de..bd14a38 100644 --- a/Tools/DumpRenderTree/win/ImageDiffProduction.vsprops +++ b/Tools/DumpRenderTree/win/ImageDiffProduction.vsprops @@ -5,7 +5,7 @@ Name="ImageDiffProduction" InheritedPropertySheets=" $(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\common.vsprops; - $(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\release.vsprops; + $(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\releaseproduction.vsprops; $(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\production.vsprops; .\ImageDiffCommon.vsprops" > diff --git a/Tools/DumpRenderTree/win/ImageDiffRelease.vsprops b/Tools/DumpRenderTree/win/ImageDiffRelease.vsprops index 79e9749..16ba125 100644 --- a/Tools/DumpRenderTree/win/ImageDiffRelease.vsprops +++ b/Tools/DumpRenderTree/win/ImageDiffRelease.vsprops @@ -5,6 +5,7 @@ Name="ImageDiffRelease" InheritedPropertySheets=" $(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\common.vsprops; + $(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\releaseproduction.vsprops; $(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\release.vsprops; .\ImageDiffCommon.vsprops" > diff --git a/Tools/DumpRenderTree/win/ImageDiffReleaseCairoCFLite.vsprops b/Tools/DumpRenderTree/win/ImageDiffReleaseCairoCFLite.vsprops index 1cb062b..7ca4b32 100644 --- a/Tools/DumpRenderTree/win/ImageDiffReleaseCairoCFLite.vsprops +++ b/Tools/DumpRenderTree/win/ImageDiffReleaseCairoCFLite.vsprops @@ -5,8 +5,9 @@ Name="ImageDiffReleaseCairoCFLite" InheritedPropertySheets=" $(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\common.vsprops; + $(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\releaseproduction.vsprops; $(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\release.vsprops; $(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\WinCairo.vsprops; - .\ImageDiffCommon.vsprops" + .\ImageDiffWinCairoCommon.vsprops" > </VisualStudioPropertySheet> diff --git a/Tools/DumpRenderTree/win/ImageDiffWinCairoCommon.vsprops b/Tools/DumpRenderTree/win/ImageDiffWinCairoCommon.vsprops new file mode 100644 index 0000000..eb1b922 --- /dev/null +++ b/Tools/DumpRenderTree/win/ImageDiffWinCairoCommon.vsprops @@ -0,0 +1,18 @@ +<?xml version="1.0" encoding="Windows-1252"?> +<VisualStudioPropertySheet + ProjectType="Visual C++" + Version="8.00" + Name="ImageDiffCommon" + > + <Tool + Name="VCCLCompilerTool" + AdditionalIncludeDirectories=""$(ConfigurationBuildDir)\include";"$(ConfigurationBuildDir)\include\private";"$(ConfigurationBuildDir)\include\WebCore\ForwardingHeaders";"$(WebKitLibrariesDir)\include";"$(WebKitLibrariesDir)\include\private"" + PreprocessorDefinitions="NOMINMAX" + /> + <Tool + Name="VCLinkerTool" + AdditionalOptions="/NXCOMPAT" + AdditionalDependencies="JavaScriptCore$(WebKitDLLConfigSuffix).lib cairo$(LibraryConfigSuffix).lib libjpeg.lib libpng$(LibraryConfigSuffix).lib zlib.lib Msimg32.lib CFLite$(LibraryConfigSuffix).lib" + SubSystem="1" + /> +</VisualStudioPropertySheet> diff --git a/Tools/DumpRenderTree/win/LayoutTestControllerWin.cpp b/Tools/DumpRenderTree/win/LayoutTestControllerWin.cpp index 1d2f3d8..2086ae7 100644 --- a/Tools/DumpRenderTree/win/LayoutTestControllerWin.cpp +++ b/Tools/DumpRenderTree/win/LayoutTestControllerWin.cpp @@ -1441,6 +1441,12 @@ void LayoutTestController::setEditingBehavior(const char* editingBehavior) preferences->setEditingBehavior(WebKitEditingUnixBehavior); } +JSValueRef LayoutTestController::shadowRoot(JSContextRef context, JSValueRef jsElement) +{ + // FIXME: Implement this. + return JSValueMakeUndefined(context); +} + void LayoutTestController::abortModal() { } diff --git a/Tools/DumpRenderTree/win/PixelDumpSupportWin.cpp b/Tools/DumpRenderTree/win/PixelDumpSupportWin.cpp index 752cc39..f7a95d3 100644 --- a/Tools/DumpRenderTree/win/PixelDumpSupportWin.cpp +++ b/Tools/DumpRenderTree/win/PixelDumpSupportWin.cpp @@ -28,15 +28,15 @@ #include "config.h" -#if PLATFORM(CG) +#if USE(CG) #include "PixelDumpSupportCG.h" -#elif PLATFORM(CAIRO) +#elif USE(CAIRO) #include "PixelDumpSupportCairo.h" #endif #include "DumpRenderTree.h" -#if PLATFORM(CG) +#if USE(CG) // Note: Must be included *after* DumpRenderTree.h to avoid compile error. #include <CoreGraphics/CGBitmapContext.h> #endif @@ -70,11 +70,11 @@ PassRefPtr<BitmapContext> createBitmapContextFromWebView(bool onscreen, bool inc GetObject(bitmap, sizeof(info), &info); ASSERT(info.bmBitsPixel == 32); -#if PLATFORM(CG) +#if USE(CG) RetainPtr<CGColorSpaceRef> colorSpace(AdoptCF, CGColorSpaceCreateDeviceRGB()); CGContextRef context = CGBitmapContextCreate(info.bmBits, info.bmWidth, info.bmHeight, 8, info.bmWidthBytes, colorSpace.get(), kCGBitmapByteOrder32Host | kCGImageAlphaPremultipliedFirst); -#elif PLATFORM(CAIRO) +#elif USE(CAIRO) cairo_surface_t* image = cairo_image_surface_create_for_data((unsigned char*)info.bmBits, CAIRO_FORMAT_ARGB32, info.bmWidth, info.bmHeight, info.bmWidthBytes); cairo_t* context = cairo_create(image); diff --git a/Tools/DumpRenderTree/wx/LayoutTestControllerWx.cpp b/Tools/DumpRenderTree/wx/LayoutTestControllerWx.cpp index c45ea0e..b2a1f58 100644 --- a/Tools/DumpRenderTree/wx/LayoutTestControllerWx.cpp +++ b/Tools/DumpRenderTree/wx/LayoutTestControllerWx.cpp @@ -612,3 +612,9 @@ void LayoutTestController::deleteLocalStorageForOrigin(JSStringRef URL) { // FIXME: Implement. } + +const OpaqueJSValue* LayoutTestController::shadowRoot(const OpaqueJSContext*, const OpaqueJSValue*) +{ + // FIXME: Implement. + return 0; +} diff --git a/Tools/FindSafari/FindSafariProduction.vsprops b/Tools/FindSafari/FindSafariProduction.vsprops index c2d3e36..afb7d22 100644 --- a/Tools/FindSafari/FindSafariProduction.vsprops +++ b/Tools/FindSafari/FindSafariProduction.vsprops @@ -5,7 +5,7 @@ Name="FindSafariProduction" InheritedPropertySheets=" $(WebKitVSPropsRedirectionDir)..\..\WebKitLibraries\win\tools\vsprops\common.vsprops; - $(WebKitVSPropsRedirectionDir)..\..\WebKitLibraries\win\tools\vsprops\release.vsprops; + $(WebKitVSPropsRedirectionDir)..\..\WebKitLibraries\win\tools\vsprops\releaseproduction.vsprops; $(WebKitVSPropsRedirectionDir)..\..\WebKitLibraries\win\tools\vsprops\production.vsprops; .\FindSafariCommon.vsprops" > diff --git a/Tools/FindSafari/FindSafariRelease.vsprops b/Tools/FindSafari/FindSafariRelease.vsprops index 9d59b3d..ca994f4 100644 --- a/Tools/FindSafari/FindSafariRelease.vsprops +++ b/Tools/FindSafari/FindSafariRelease.vsprops @@ -5,6 +5,7 @@ Name="FindSafariRelease" InheritedPropertySheets=" $(WebKitVSPropsRedirectionDir)..\..\WebKitLibraries\win\tools\vsprops\common.vsprops; + $(WebKitVSPropsRedirectionDir)..\..\WebKitLibraries\win\tools\vsprops\releaseproduction.vsprops; $(WebKitVSPropsRedirectionDir)..\..\WebKitLibraries\win\tools\vsprops\release.vsprops; .\FindSafariCommon.vsprops" > diff --git a/Tools/FindSafari/FindSafariReleaseCairoCFLite.vsprops b/Tools/FindSafari/FindSafariReleaseCairoCFLite.vsprops index fccbb9c..b1e4748 100644 --- a/Tools/FindSafari/FindSafariReleaseCairoCFLite.vsprops +++ b/Tools/FindSafari/FindSafariReleaseCairoCFLite.vsprops @@ -5,6 +5,7 @@ Name="FindSafariReleaseCairoCFLite" InheritedPropertySheets=" $(WebKitVSPropsRedirectionDir)..\..\WebKitLibraries\win\tools\vsprops\common.vsprops; + $(WebKitVSPropsRedirectionDir)..\..\WebKitLibraries\win\tools\vsprops\releaseproduction.vsprops; $(WebKitVSPropsRedirectionDir)..\..\WebKitLibraries\win\tools\vsprops\release.vsprops; $(WebKitVSPropsRedirectionDir)..\..\WebKitLibraries\win\tools\vsprops\WinCairo.vsprops; .\FindSafariCommon.vsprops" diff --git a/Tools/FindSafari/FindSafariReleasePGO.vsprops b/Tools/FindSafari/FindSafariReleasePGO.vsprops index 6c24cbc..1755933 100644 --- a/Tools/FindSafari/FindSafariReleasePGO.vsprops +++ b/Tools/FindSafari/FindSafariReleasePGO.vsprops @@ -5,7 +5,7 @@ Name="FindSafariReleasePGO" InheritedPropertySheets=" $(WebKitVSPropsRedirectionDir)..\..\WebKitLibraries\win\tools\vsprops\common.vsprops; - $(WebKitVSPropsRedirectionDir)..\..\WebKitLibraries\win\tools\vsprops\release.vsprops; + $(WebKitVSPropsRedirectionDir)..\..\WebKitLibraries\win\tools\vsprops\releaseproduction.vsprops; $(WebKitVSPropsRedirectionDir)..\..\WebKitLibraries\win\tools\vsprops\production.vsprops; .\FindSafariCommon.vsprops" > diff --git a/Tools/GNUmakefile.am b/Tools/GNUmakefile.am index 6de1af5..34052d7 100644 --- a/Tools/GNUmakefile.am +++ b/Tools/GNUmakefile.am @@ -56,6 +56,8 @@ Programs_DumpRenderTree_SOURCES = \ Tools/DumpRenderTree/AccessibilityTextMarker.h \ Tools/DumpRenderTree/AccessibilityUIElement.cpp \ Tools/DumpRenderTree/AccessibilityUIElement.h \ + Tools/DumpRenderTree/CyclicRedundancyCheck.cpp \ + Tools/DumpRenderTree/CyclicRedundancyCheck.h \ Tools/DumpRenderTree/GCController.cpp \ Tools/DumpRenderTree/GCController.h \ Tools/DumpRenderTree/JavaScriptThreading.h \ @@ -82,6 +84,8 @@ Programs_DumpRenderTree_SOURCES = \ Tools/DumpRenderTree/gtk/GCControllerGtk.cpp \ Tools/DumpRenderTree/gtk/LayoutTestControllerGtk.cpp \ Tools/DumpRenderTree/gtk/PixelDumpSupportGtk.cpp \ + Tools/DumpRenderTree/gtk/PlainTextController.cpp \ + Tools/DumpRenderTree/gtk/PlainTextController.h \ Tools/DumpRenderTree/gtk/TextInputController.h \ Tools/DumpRenderTree/gtk/TextInputController.cpp \ Tools/DumpRenderTree/gtk/WorkQueueItemGtk.cpp \ @@ -181,6 +185,7 @@ TestNetscapePlugin_libtestnetscapeplugin_la_SOURCES = \ Tools/DumpRenderTree/TestNetscapePlugIn/Tests/GetURLWithJavaScriptURLDestroyingPlugin.cpp \ Tools/DumpRenderTree/TestNetscapePlugIn/Tests/GetUserAgentWithNullNPPFromNPPNew.cpp \ Tools/DumpRenderTree/TestNetscapePlugIn/Tests/NPDeallocateCalledBeforeNPShutdown.cpp \ + Tools/DumpRenderTree/TestNetscapePlugIn/Tests/NPPSetWindowCalledDuringDestruction.cpp \ Tools/DumpRenderTree/TestNetscapePlugIn/Tests/NPRuntimeObjectFromDestroyedPlugin.cpp \ Tools/DumpRenderTree/TestNetscapePlugIn/Tests/NPRuntimeRemoveProperty.cpp \ Tools/DumpRenderTree/TestNetscapePlugIn/Tests/NullNPPGetValuePointer.cpp \ diff --git a/Tools/GtkLauncher/main.c b/Tools/GtkLauncher/main.c index ad666e2..a1baf05 100644 --- a/Tools/GtkLauncher/main.c +++ b/Tools/GtkLauncher/main.c @@ -230,24 +230,6 @@ static gchar* filenameToURL(const char* filename) return fileURL; } -#ifndef GTK_API_VERSION_2 -static void disablePlugin(const char* pluginName) -{ - WebKitWebPluginDatabase *database = webkit_get_web_plugin_database(); - GSList *plugins = webkit_web_plugin_database_get_plugins(database); - GSList *p; - - for (p = plugins; p; p = g_slist_next(p)) { - WebKitWebPlugin *plugin = WEBKIT_WEB_PLUGIN(p->data); - - if (!g_strcmp0(webkit_web_plugin_get_name(plugin), pluginName)) - webkit_web_plugin_set_enabled(plugin, FALSE); - } - - webkit_web_plugin_database_plugins_list_free(plugins); -} -#endif - int main(int argc, char* argv[]) { WebKitWebView *webView; @@ -257,10 +239,6 @@ int main(int argc, char* argv[]) if (!g_thread_supported()) g_thread_init(NULL); -#ifndef GTK_API_VERSION_2 - disablePlugin("Shockwave Flash"); -#endif - main_window = createWindow(&webView); gchar *uri =(gchar*)(argc > 1 ? argv[1] : "http://www.google.com/"); diff --git a/Tools/MiniBrowser/Configurations/MiniBrowserProduction.vsprops b/Tools/MiniBrowser/Configurations/MiniBrowserProduction.vsprops index 75195e3..4c5e11b 100644 --- a/Tools/MiniBrowser/Configurations/MiniBrowserProduction.vsprops +++ b/Tools/MiniBrowser/Configurations/MiniBrowserProduction.vsprops @@ -5,7 +5,7 @@ Name="MiniBrowserProduction" InheritedPropertySheets=" $(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\common.vsprops; - $(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\release.vsprops; + $(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\releaseproduction.vsprops; $(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\production.vsprops; .\MiniBrowserCoreFoundation.vsprops; .\MiniBrowserCommon.vsprops" diff --git a/Tools/MiniBrowser/Configurations/MiniBrowserRelease.vsprops b/Tools/MiniBrowser/Configurations/MiniBrowserRelease.vsprops index 27af48a..653d847 100644 --- a/Tools/MiniBrowser/Configurations/MiniBrowserRelease.vsprops +++ b/Tools/MiniBrowser/Configurations/MiniBrowserRelease.vsprops @@ -5,6 +5,7 @@ Name="MiniBrowserRelease" InheritedPropertySheets=" $(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\common.vsprops; + $(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\releaseproduction.vsprops; $(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\release.vsprops; .\MiniBrowserCoreFoundation.vsprops; .\MiniBrowserCommon.vsprops" diff --git a/Tools/MiniBrowser/Configurations/MiniBrowserReleaseCairoCFLite.vsprops b/Tools/MiniBrowser/Configurations/MiniBrowserReleaseCairoCFLite.vsprops index a50d5b7..bf485fc 100644 --- a/Tools/MiniBrowser/Configurations/MiniBrowserReleaseCairoCFLite.vsprops +++ b/Tools/MiniBrowser/Configurations/MiniBrowserReleaseCairoCFLite.vsprops @@ -5,6 +5,7 @@ Name="MiniBrowserReleaseCairoCFLite" InheritedPropertySheets=" $(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\common.vsprops; + $(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\releaseproduction.vsprops; $(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\release.vsprops; $(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\WinCairo.vsprops; .\MiniBrowserCFLite.vsprops; diff --git a/Tools/MiniBrowser/DerivedSources.pro b/Tools/MiniBrowser/DerivedSources.pro deleted file mode 100644 index 8674beb..0000000 --- a/Tools/MiniBrowser/DerivedSources.pro +++ /dev/null @@ -1,33 +0,0 @@ -# DerivedSources - qmake build info - -CONFIG -= debug_and_release - -TEMPLATE = lib -TARGET = dummy - -QMAKE_EXTRA_TARGETS += generated_files - -isEmpty(OUTPUT_DIR): OUTPUT_DIR = ../.. -SRC_ROOT_DIR = $$replace(PWD, "/Tools/MiniBrowser", "") - -!exists($$OUTPUT_DIR/MiniBrowser/qt): system($$QMAKE_MKDIR $$OUTPUT_DIR/MiniBrowser/qt) - -ualist_copier.input = $$SRC_ROOT_DIR/Tools/QtTestBrowser/useragentlist.txt -ualist_copier.output = $$OUTPUT_DIR/MiniBrowser/qt/useragentlist.txt -ualist_copier.tempNames = $$ualist_copier.input $$ualist_copier.output -ualist_copier.commands = $$QMAKE_COPY $$replace(ualist_copier.tempNames, "/", $$QMAKE_DIR_SEP) -ualist_copier.depends = $$ualist_copier.input -generated_files.depends += ualist_copier -QMAKE_EXTRA_TARGETS += ualist_copier - -# We have to copy the resource file to the build directory -# to use the useragentlist.txt file of QtTestBrowser without -# polluting the source tree. - -qrc_copier.input = $$SRC_ROOT_DIR/Tools/MiniBrowser/MiniBrowser.qrc -qrc_copier.output = $$OUTPUT_DIR/MiniBrowser/qt/MiniBrowser.qrc -qrc_copier.tempNames = $$qrc_copier.input $$qrc_copier.output -qrc_copier.commands = $$QMAKE_COPY $$replace(qrc_copier.tempNames, "/", $$QMAKE_DIR_SEP) -qrc_copier.depends = ualist_copier $$qrc_copier.input -generated_files.depends += qrc_copier -QMAKE_EXTRA_TARGETS += qrc_copier diff --git a/Tools/MiniBrowser/gtk/GNUmakefile.am b/Tools/MiniBrowser/gtk/GNUmakefile.am new file mode 100644 index 0000000..24da0ad --- /dev/null +++ b/Tools/MiniBrowser/gtk/GNUmakefile.am @@ -0,0 +1,33 @@ +bin_PROGRAMS += \ + Programs/MiniBrowser + +Programs_MiniBrowser_CPPFLAGS = \ + -I$(srcdir)/Source \ + -I$(top_builddir)/DerivedSources/WebKit2/include \ + $(global_cppflags) \ + $(GLIB_CFLAGS) \ + $(GTK_CFLAGS) + +Programs_MiniBrowser_SOURCES = \ + Tools/MiniBrowser/gtk/main.c + +BUILT_SOURCES += \ + generate-minibrowser-forward-headers + +MiniBrowser := $(srcdir)/Tools/MiniBrowser/gtk +MiniBrowserFwdHeaders := $(GENSOURCES_WEBKIT2)/include +generate-minibrowser-forward-headers: $(WebKit2)/Scripts/generate-forwarding-headers.pl $(Programs_MiniBrowser_SOURCES) + $(AM_V_GEN)$(PERL) $< $(MiniBrowser) $(MiniBrowserFwdHeaders) gtk + $(AM_V_GEN)$(PERL) $< $(MiniBrowser) $(MiniBrowserFwdHeaders) soup + +Programs_MiniBrowser_LDADD = \ + libwebkit2gtk-@WEBKITGTK_API_MAJOR_VERSION@.@WEBKITGTK_API_MINOR_VERSION@.la \ + $(GLIB_LIBS) \ + $(GTK_LIBS) + +Programs_MiniBrowser_LDFLAGS = \ + -no-fast-install \ + -no-install + +CLEANFILES += \ + $(top_builddir)/Programs/MiniBrowser diff --git a/Tools/MiniBrowser/gtk/main.c b/Tools/MiniBrowser/gtk/main.c new file mode 100644 index 0000000..0c32510 --- /dev/null +++ b/Tools/MiniBrowser/gtk/main.c @@ -0,0 +1,138 @@ +/* + * Copyright (C) 2006, 2007 Apple Inc. + * Copyright (C) 2007 Alp Toker <alp@atoker.com> + * Copyright (C) 2011 Igalia S.L. + * + * 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. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 COMPUTER, INC. OR + * 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. + */ + +#include <WebKit2/WebKit2.h> +#include <gtk/gtk.h> + +static void activateUriEntryCallback(GtkWidget *entry, gpointer data) +{ + WKViewRef webView = g_object_get_data(G_OBJECT(entry), "web-view"); + const gchar *uri = gtk_entry_get_text(GTK_ENTRY(entry)); + WKPageLoadURL(WKViewGetPage(webView), WKURLCreateWithURL(uri)); +} + +static void destroyCallback(GtkWidget *widget, GtkWidget *window) +{ + gtk_main_quit(); +} + +static void goBackCallback(GtkWidget *widget, WKViewRef webView) +{ + WKPageGoBack(WKViewGetPage(webView)); +} + +static void goForwardCallback(GtkWidget *widget, WKViewRef webView) +{ + WKPageGoForward(WKViewGetPage(webView)); +} + +static GtkWidget *createToolbar(GtkWidget *uriEntry, WKViewRef webView) +{ + GtkWidget *toolbar = gtk_toolbar_new(); + +#if GTK_CHECK_VERSION(2, 15, 0) + gtk_orientable_set_orientation(GTK_ORIENTABLE(toolbar), GTK_ORIENTATION_HORIZONTAL); +#else + gtk_toolbar_set_orientation(GTK_TOOLBAR(toolbar), GTK_ORIENTATION_HORIZONTAL); +#endif + gtk_toolbar_set_style(GTK_TOOLBAR(toolbar), GTK_TOOLBAR_BOTH_HORIZ); + + GtkToolItem *item = gtk_tool_button_new_from_stock(GTK_STOCK_GO_BACK); + g_signal_connect(item, "clicked", G_CALLBACK(goBackCallback), (gpointer)webView); + gtk_toolbar_insert(GTK_TOOLBAR(toolbar), item, -1); + + item = gtk_tool_button_new_from_stock(GTK_STOCK_GO_FORWARD); + g_signal_connect(G_OBJECT(item), "clicked", G_CALLBACK(goForwardCallback), (gpointer)webView); + gtk_toolbar_insert(GTK_TOOLBAR(toolbar), item, -1); + + item = gtk_tool_item_new(); + gtk_tool_item_set_expand(item, TRUE); + gtk_container_add(GTK_CONTAINER(item), uriEntry); + g_signal_connect(uriEntry, "activate", G_CALLBACK(activateUriEntryCallback), NULL); + gtk_toolbar_insert(GTK_TOOLBAR(toolbar), item, -1); + + g_object_set_data(G_OBJECT(uriEntry), "web-view", (gpointer)webView); + item = gtk_tool_button_new_from_stock(GTK_STOCK_OK); + g_signal_connect_swapped(item, "clicked", G_CALLBACK(activateUriEntryCallback), (gpointer)uriEntry); + gtk_toolbar_insert(GTK_TOOLBAR(toolbar), item, -1); + + return toolbar; +} + +static WKViewRef createWebView() +{ + return WKViewCreate(WKContextGetSharedProcessContext(), 0); +} + +static GtkWidget *createWindow(WKViewRef webView) +{ + GtkWidget *window = gtk_window_new(GTK_WINDOW_TOPLEVEL); + gtk_window_set_default_size(GTK_WINDOW(window), 800, 600); + gtk_widget_set_name(window, "MiniBrowser"); + + GtkWidget *uriEntry = gtk_entry_new(); + + GtkWidget *vbox = gtk_vbox_new(FALSE, 0); + gtk_box_pack_start(GTK_BOX(vbox), createToolbar(uriEntry, webView), FALSE, FALSE, 0); + gtk_box_pack_start(GTK_BOX(vbox), WKViewGetWindow(webView), TRUE, TRUE, 0); + + gtk_container_add(GTK_CONTAINER(window), vbox); + + g_signal_connect(window, "destroy", G_CALLBACK(destroyCallback), NULL); + + return window; +} + +static gchar *argumentToURL(const char *filename) +{ + GFile *gfile = g_file_new_for_commandline_arg(filename); + gchar *fileURL = g_file_get_uri(gfile); + g_object_unref(gfile); + + return fileURL; +} + +int main(int argc, char *argv[]) +{ + gtk_init(&argc, &argv); + + if (!g_thread_supported()) + g_thread_init(NULL); + + WKViewRef webView = createWebView(); + GtkWidget *mainWindow = createWindow(webView); + + gchar* url = argumentToURL(argc > 1 ? argv[1] : "http://www.webkitgtk.org/"); + WKPageLoadURL(WKViewGetPage(webView), WKURLCreateWithURL(url)); + g_free(url); + + gtk_widget_grab_focus(WKViewGetWindow(webView)); + gtk_widget_show_all(mainWindow); + gtk_main(); + + return 0; +} diff --git a/Tools/MiniBrowser/mac/BrowserWindowController.m b/Tools/MiniBrowser/mac/BrowserWindowController.m index 1f6fc04..f6b4d1d 100644 --- a/Tools/MiniBrowser/mac/BrowserWindowController.m +++ b/Tools/MiniBrowser/mac/BrowserWindowController.m @@ -618,6 +618,9 @@ static void runOpenPanel(WKPageRef page, WKFrameRef frame, WKOpenPanelParameters createNewPage, showPage, closePage, + 0, /* takeFocus */ + 0, /* focus */ + 0, /* unfocus */ runJavaScriptAlert, runJavaScriptConfirm, runJavaScriptPrompt, diff --git a/Tools/MiniBrowser/qt/BrowserWindow.cpp b/Tools/MiniBrowser/qt/BrowserWindow.cpp index 53f7de9..a8a2226 100644 --- a/Tools/MiniBrowser/qt/BrowserWindow.cpp +++ b/Tools/MiniBrowser/qt/BrowserWindow.cpp @@ -28,6 +28,7 @@ #include "BrowserWindow.h" +#include "UrlLoader.h" #include "qwkpreferences.h" static QWKPage* newPageFunction(QWKPage* page) @@ -41,6 +42,7 @@ QVector<qreal> BrowserWindow::m_zoomLevels; BrowserWindow::BrowserWindow(QWKContext* context, WindowOptions* options) : m_isZoomTextOnly(false) , m_currentZoom(1) + , m_urlLoader(0) , m_context(context) { if (options) @@ -106,6 +108,8 @@ BrowserWindow::BrowserWindow(QWKContext* context, WindowOptions* options) toggleFrameFlattening->setChecked(false); toolsMenu->addSeparator(); toolsMenu->addAction("Change User Agent", this, SLOT(showUserAgentDialog())); + toolsMenu->addSeparator(); + toolsMenu->addAction("Load URLs from file", this, SLOT(loadURLListFromFile())); QMenu* settingsMenu = menuBar()->addMenu("&Settings"); QAction* toggleAutoLoadImages = settingsMenu->addAction("Disable Auto Load Images", this, SLOT(toggleAutoLoadImages(bool))); @@ -137,7 +141,10 @@ BrowserWindow::BrowserWindow(QWKContext* context, WindowOptions* options) m_zoomLevels << 1.1 << 1.2 << 1.33 << 1.5 << 1.7 << 2 << 2.4 << 3; } - resize(800, 600); + if (m_windowOptions.startMaximized) + setWindowState(windowState() | Qt::WindowMaximized); + else + resize(800, 600); show(); } @@ -294,10 +301,9 @@ void BrowserWindow::toggleZoomTextOnly(bool b) void BrowserWindow::toggleFullScreenMode(bool enable) { - if (enable) - setWindowState(Qt::WindowFullScreen); - else - setWindowState(Qt::WindowNoState); + bool alreadyEnabled = windowState() & Qt::WindowFullScreen; + if (enable ^ alreadyEnabled) + setWindowState(windowState() ^ Qt::WindowFullScreen); } void BrowserWindow::toggleFrameFlattening(bool toggle) @@ -335,6 +341,20 @@ void BrowserWindow::showUserAgentDialog() page()->setCustomUserAgent(combo->currentText()); } +void BrowserWindow::loadURLListFromFile() +{ + QString selectedFile; +#ifndef QT_NO_FILEDIALOG + selectedFile = QFileDialog::getOpenFileName(this, tr("Load URL list from file") + , QString(), tr("Text Files (*.txt);;All Files (*)")); +#endif + if (selectedFile.isEmpty()) + return; + + m_urlLoader = new UrlLoader(this, selectedFile, 0, 0); + m_urlLoader->loadNext(); +} + void BrowserWindow::printURL(const QUrl& url) { QTextStream output(stdout); @@ -380,6 +400,7 @@ void BrowserWindow::applyZoom() BrowserWindow::~BrowserWindow() { + delete m_urlLoader; delete m_addressBar; delete m_browser; } diff --git a/Tools/MiniBrowser/qt/BrowserWindow.h b/Tools/MiniBrowser/qt/BrowserWindow.h index 6ad8f27..06da2a2 100644 --- a/Tools/MiniBrowser/qt/BrowserWindow.h +++ b/Tools/MiniBrowser/qt/BrowserWindow.h @@ -35,6 +35,8 @@ #include <QStringList> #include <QtGui> +class UrlLoader; + class BrowserWindow : public QMainWindow { Q_OBJECT @@ -69,6 +71,8 @@ protected slots: void toggleFrameFlattening(bool); void showUserAgentDialog(); + void loadURLListFromFile(); + void printURL(const QUrl&); void toggleAutoLoadImages(bool); @@ -83,6 +87,7 @@ private: bool m_isZoomTextOnly; qreal m_currentZoom; + UrlLoader* m_urlLoader; QWKContext* m_context; WindowOptions m_windowOptions; BrowserView* m_browser; diff --git a/Tools/MiniBrowser/qt/MiniBrowser.pro b/Tools/MiniBrowser/qt/MiniBrowser.pro index 809c934..7836e53 100644 --- a/Tools/MiniBrowser/qt/MiniBrowser.pro +++ b/Tools/MiniBrowser/qt/MiniBrowser.pro @@ -58,7 +58,5 @@ contains(QT_CONFIG, opengl) { DEFINES -= QT_ASCII_CAST_WARNINGS -# We copy the resource file to the build directory. -# The copier is defined in Tools/MiniBrowser/DerivedSources.pro. -RESOURCES += \ - $$OUTPUT_DIR/MiniBrowser/qt/MiniBrowser.qrc +# Use the MiniBrowser.qrc file from the sources. +RESOURCES += MiniBrowser.qrc diff --git a/Tools/MiniBrowser/MiniBrowser.qrc b/Tools/MiniBrowser/qt/MiniBrowser.qrc index ffe77b0..ffe77b0 100644 --- a/Tools/MiniBrowser/MiniBrowser.qrc +++ b/Tools/MiniBrowser/qt/MiniBrowser.qrc diff --git a/Tools/MiniBrowser/qt/MiniBrowserApplication.cpp b/Tools/MiniBrowser/qt/MiniBrowserApplication.cpp index f40c870..912419b 100644 --- a/Tools/MiniBrowser/qt/MiniBrowserApplication.cpp +++ b/Tools/MiniBrowser/qt/MiniBrowserApplication.cpp @@ -55,6 +55,7 @@ void MiniBrowserApplication::handleUserOptions() if (args.contains("-help")) { qDebug() << "Usage:" << programName.toLatin1().data() + << "[-maximize]" << "[-r list]" << "[-robot-timeout seconds]" << "[-robot-extra-time seconds]" @@ -65,6 +66,9 @@ void MiniBrowserApplication::handleUserOptions() appQuit(0); } + if (args.contains("-maximize")) + m_windowOptions.startMaximized = true; + int robotIndex = args.indexOf("-r"); if (robotIndex != -1) { QString listFile = takeOptionValue(&args, robotIndex); diff --git a/Tools/MiniBrowser/qt/MiniBrowserApplication.h b/Tools/MiniBrowser/qt/MiniBrowserApplication.h index 5a78820..2eba9b5 100644 --- a/Tools/MiniBrowser/qt/MiniBrowserApplication.h +++ b/Tools/MiniBrowser/qt/MiniBrowserApplication.h @@ -37,12 +37,18 @@ struct WindowOptions { : useTiledBackingStore(true) , useSeparateWebProcessPerWindow(false) , printLoadedUrls(false) +#if defined(Q_OS_SYMBIAN) + , startMaximized(true) +#else + , startMaximized(false) +#endif { } bool useTiledBackingStore; bool useSeparateWebProcessPerWindow; bool printLoadedUrls; + bool startMaximized; }; class MiniBrowserApplication : public QApplication { diff --git a/Tools/MiniBrowser/qt/UrlLoader.cpp b/Tools/MiniBrowser/qt/UrlLoader.cpp index 600d477..54854c8 100644 --- a/Tools/MiniBrowser/qt/UrlLoader.cpp +++ b/Tools/MiniBrowser/qt/UrlLoader.cpp @@ -47,7 +47,7 @@ UrlLoader::UrlLoader(BrowserWindow* browserWindow, const QString& inputFileName, if (timeoutSeconds) { m_timeoutTimer.setInterval(timeoutSeconds * 1000); m_timeoutTimer.setSingleShot(true); - connect(m_browserWindow, SIGNAL(loadStarted()), &m_timeoutTimer, SLOT(start())); + connect(m_browserWindow->page(), SIGNAL(loadStarted()), &m_timeoutTimer, SLOT(start())); connect(&m_timeoutTimer, SIGNAL(timeout()), this, SLOT(loadNext())); } if (extraTimeSeconds) { diff --git a/Tools/MiniBrowser/qt/main.cpp b/Tools/MiniBrowser/qt/main.cpp index 8f4c1ea..8b38912 100644 --- a/Tools/MiniBrowser/qt/main.cpp +++ b/Tools/MiniBrowser/qt/main.cpp @@ -51,9 +51,9 @@ int main(int argc, char** argv) QStringList urls = app.urls(); if (urls.isEmpty()) { - QString defaultUrl = QString("file://%1/%2").arg(QDir::homePath()).arg(QLatin1String("index.html")); - if (QDir(defaultUrl).exists()) - urls.append(defaultUrl); + QString defaultIndexFile = QString("%1/%2").arg(QDir::homePath()).arg(QLatin1String("index.html")); + if (QFile(defaultIndexFile).exists()) + urls.append(QString("file://") + defaultIndexFile); else urls.append("http://www.google.com"); } diff --git a/Tools/MiniBrowser/qt/useragentlist.txt b/Tools/MiniBrowser/qt/useragentlist.txt new file mode 100644 index 0000000..0b29d40 --- /dev/null +++ b/Tools/MiniBrowser/qt/useragentlist.txt @@ -0,0 +1,11 @@ +Mozilla/5.0 (X11; U; Linux; en-US) AppleWebKit/533.3 (KHTML, like Gecko) QtTestBrowser/0.1 Safari/533.3 +Mozilla/5.0 (SymbianOS/9.4; U; Series60/5.0; en-GB) AppleWebKit/533.3 (KHTML, like Gecko) QtTestBrowser/0.1 Mobile Safari/533.3 +Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en) AppleWebKit/125.2 (KHTML, like Gecko) Safari/125.8 +Mozilla/5.0 (Linux; U; Android 1.1; en-gb; dream) AppleWebKit/525.10+ (KHTML, like Gecko) Version/3.0.4 Mobile Safari/523.12.2 +Mozilla/5.0 (Unknown; like Android 2.2; U; Intel Mac OS X 10_6; en-gb) AppleWebKit/533.3 (KHTML, like Gecko) Version/4.0.3 Mobile Safari/533.3 +Mozilla/5.0 (iPhone; U; CPU OS 3_2 like Mac OS X; en-us) AppleWebKit/531.21.10 (KHTML, like Gecko) Version/4.0.4 Mobile/7B334b Safari/531.21.10 +Mozilla/5.0 (iPhone; U; CPU iPhone OS 4_0 like Mac OS X; en-us) AppleWebKit/532.9 (KHTML, like Gecko) Version/4.0.5 Mobile/8A293 Safari/6531.22.7 +Mozilla/5.0(iPad; U; CPU iPhone OS 3_2 like Mac OS X; en-us) AppleWebKit/531.21.10 (KHTML, like Gecko) Version/4.0.4 Mobile/7B314 Safari/531.21.10 +Opera/9.25 (Windows NT 6.0; U; en) +Mozilla/5.0 (SymbianOS/9.4; U; Series60/5.0 Nokia5800d-1b/20.2.014; Profile/MIDP-2.1 Configuration/CLDC-1.1 ) AppleWebKit/413 (KHTML, like Gecko) Safari/413 +Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.2; Trident/4.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0) diff --git a/Tools/MiniBrowser/win/BrowserView.cpp b/Tools/MiniBrowser/win/BrowserView.cpp index f9ccfe7..76b8d04 100644 --- a/Tools/MiniBrowser/win/BrowserView.cpp +++ b/Tools/MiniBrowser/win/BrowserView.cpp @@ -98,6 +98,9 @@ void BrowserView::create(RECT webViewRect, BrowserWindow* parentWindow) createNewPage, showPage, closePage, + 0, /* takeFocus */ + 0, /* focus */ + 0, /* unfocus */ runJavaScriptAlert, runJavaScriptConfirm, runJavaScriptPrompt, diff --git a/Tools/MiniBrowser/win/main.cpp b/Tools/MiniBrowser/win/main.cpp index 0c125ba..93b47ce 100644 --- a/Tools/MiniBrowser/win/main.cpp +++ b/Tools/MiniBrowser/win/main.cpp @@ -41,6 +41,22 @@ #pragma comment(linker, "/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='" PROCESSORARCHITECTURE "' publicKeyToken='6595b64144ccf1df' language='*'\"") +static bool shouldTranslateMessage(const MSG& msg) +{ + // Only these four messages are actually translated by ::TranslateMessage or ::TranslateAccelerator. + // It's useless (though harmless) to call those functions for other messages, so we always allow other messages to be translated. + if (msg.message != WM_KEYDOWN && msg.message != WM_SYSKEYDOWN && msg.message != WM_KEYUP && msg.message != WM_SYSKEYUP) + return true; + + wchar_t className[256]; + if (!::GetClassNameW(msg.hwnd, className, ARRAYSIZE(className))) + return true; + + // Don't call TranslateMessage() on key events destined for a WebKit2 view, WebKit will do this if it doesn't handle the message. + // It would be nice to use some API here instead of hard-coding the window class name. + return wcscmp(className, L"WebKit2WebViewWindowClass"); +} + int WINAPI _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpstrCmdLine, int nCmdShow) { MiniBrowser::shared().initialize(hInstance); @@ -52,7 +68,9 @@ int WINAPI _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpstrC while (BOOL result = ::GetMessage(&message, 0, 0, 0)) { if (result == -1) break; - ::TranslateMessage(&message); + + if (shouldTranslateMessage(message)) + ::TranslateMessage(&message); if (!MiniBrowser::shared().handleMessage(&message)) ::DispatchMessage(&message); diff --git a/Tools/QtTestBrowser/QtTestBrowser.pro b/Tools/QtTestBrowser/QtTestBrowser.pro index 4cd7ecb..a7826e5 100644 --- a/Tools/QtTestBrowser/QtTestBrowser.pro +++ b/Tools/QtTestBrowser/QtTestBrowser.pro @@ -22,7 +22,7 @@ HEADERS += \ webview.h \ fpstimer.h \ -CONFIG += uitools +!isEqual(QT_ARCH,sh4): CONFIG += uitools isEmpty(OUTPUT_DIR): OUTPUT_DIR = ../.. include(../../Source/WebKit.pri) @@ -34,7 +34,7 @@ DESTDIR = $$OUTPUT_DIR/bin QT += network macx:QT+=xml -unix:!mac:!symbian { +unix:!mac:!symbian:!embedded { CONFIG += link_pkgconfig PKGCONFIG += fontconfig } diff --git a/Tools/QtTestBrowser/launcherwindow.cpp b/Tools/QtTestBrowser/launcherwindow.cpp index f4db898..a6b05f4 100644 --- a/Tools/QtTestBrowser/launcherwindow.cpp +++ b/Tools/QtTestBrowser/launcherwindow.cpp @@ -31,6 +31,7 @@ */ #include "launcherwindow.h" +#include "urlloader.h" const int gExitClickArea = 80; QVector<int> LauncherWindow::m_zoomLevels; @@ -38,6 +39,7 @@ QVector<int> LauncherWindow::m_zoomLevels; LauncherWindow::LauncherWindow(WindowOptions* data, QGraphicsScene* sharedScene) : MainWindow() , m_currentZoom(100) + , m_urlLoader(0) , m_view(0) , m_inspector(0) , m_formatMenuAction(0) @@ -56,6 +58,7 @@ LauncherWindow::LauncherWindow(WindowOptions* data, QGraphicsScene* sharedScene) LauncherWindow::~LauncherWindow() { grabZoomKeys(false); + delete m_urlLoader; } void LauncherWindow::init() @@ -63,12 +66,10 @@ void LauncherWindow::init() QSplitter* splitter = new QSplitter(Qt::Vertical, this); setCentralWidget(splitter); -#if defined(Q_OS_SYMBIAN) - setWindowState(Qt::WindowMaximized); -#else - setWindowState(Qt::WindowNoState); - resize(800, 600); -#endif + if (m_windowOptions.startMaximized) + setWindowState(windowState() | Qt::WindowMaximized); + else + resize(800, 600); m_inspector = new WebInspector; #ifndef QT_NO_PROPERTIES @@ -287,6 +288,8 @@ void LauncherWindow::createChrome() QAction* showInspectorAction = toolsMenu->addAction("Show Web Inspector", m_inspector, SLOT(setVisible(bool)), QKeySequence(Qt::CTRL | Qt::ALT | Qt::Key_I)); showInspectorAction->setCheckable(true); showInspectorAction->connect(m_inspector, SIGNAL(visibleChanged(bool)), SLOT(setChecked(bool))); + toolsMenu->addSeparator(); + toolsMenu->addAction("Load URLs from file", this, SLOT(loadURLListFromFile())); // GraphicsView sub menu. QAction* toggleAcceleratedCompositing = graphicsViewMenu->addAction("Toggle Accelerated Compositing", this, SLOT(toggleAcceleratedCompositing(bool))); @@ -770,15 +773,9 @@ void LauncherWindow::toggleSpatialNavigation(bool b) void LauncherWindow::toggleFullScreenMode(bool enable) { - if (enable) - setWindowState(Qt::WindowFullScreen); - else { -#if defined(Q_OS_SYMBIAN) - setWindowState(Qt::WindowMaximized); -#else - setWindowState(Qt::WindowNoState); -#endif - } + bool alreadyEnabled = windowState() & Qt::WindowFullScreen; + if (enable ^ alreadyEnabled) + setWindowState(windowState() ^ Qt::WindowFullScreen); } void LauncherWindow::toggleFrameFlattening(bool toggle) @@ -900,6 +897,20 @@ void LauncherWindow::showUserAgentDialog() delete dialog; } +void LauncherWindow::loadURLListFromFile() +{ + QString selectedFile; +#ifndef QT_NO_FILEDIALOG + selectedFile = QFileDialog::getOpenFileName(this, tr("Load URL list from file") + , QString(), tr("Text Files (*.txt);;All Files (*)")); +#endif + if (selectedFile.isEmpty()) + return; + + m_urlLoader = new UrlLoader(this->page()->mainFrame(), selectedFile, 0, 0); + m_urlLoader->loadNext(); +} + void LauncherWindow::printURL(const QUrl& url) { QTextStream output(stdout); diff --git a/Tools/QtTestBrowser/launcherwindow.h b/Tools/QtTestBrowser/launcherwindow.h index 8bdad4d..705a1e4 100644 --- a/Tools/QtTestBrowser/launcherwindow.h +++ b/Tools/QtTestBrowser/launcherwindow.h @@ -104,6 +104,11 @@ public: , useTestFonts(false) #endif , printLoadedUrls(false) +#if defined(Q_OS_SYMBIAN) + , startMaximized(true) +#else + , startMaximized(false) +#endif { } @@ -129,6 +134,7 @@ public: bool printLoadedUrls; QUrl inspectorUrl; quint16 remoteInspectorPort; + bool startMaximized; }; class LauncherWindow : public MainWindow { @@ -165,6 +171,8 @@ protected slots: /* void dumpPlugins() */ void dumpHtml(); + void loadURLListFromFile(); + void setTouchMocking(bool on); void toggleWebView(bool graphicsBased); void toggleAcceleratedCompositing(bool toggle); @@ -217,6 +225,8 @@ private: static QVector<int> m_zoomLevels; int m_currentZoom; + UrlLoader* m_urlLoader; + QWidget* m_view; WebInspector* m_inspector; diff --git a/Tools/QtTestBrowser/main.cpp b/Tools/QtTestBrowser/main.cpp index 059269c..c44c4c6 100644 --- a/Tools/QtTestBrowser/main.cpp +++ b/Tools/QtTestBrowser/main.cpp @@ -183,6 +183,7 @@ void LauncherApplication::handleUserOptions() #endif << QString("[-viewport-update-mode %1]").arg(formatKeys(updateModes)).toLatin1().data() << "[-cache-webview]" + << "[-maximize]" << "[-show-fps]" << "[-r list]" << "[-robot-timeout seconds]" @@ -234,6 +235,9 @@ void LauncherApplication::handleUserOptions() if (args.contains("-local-storage-enabled")) windowOptions.useLocalStorage = true; + if (args.contains("-maximize")) + windowOptions.startMaximized = true; + if (args.contains("-offline-storage-database-enabled")) windowOptions.useOfflineStorageDatabase = true; diff --git a/Tools/QueueStatusServer/handlers/queuestatus.py b/Tools/QueueStatusServer/handlers/queuestatus.py index e5dc95f..9eaef6f 100644 --- a/Tools/QueueStatusServer/handlers/queuestatus.py +++ b/Tools/QueueStatusServer/handlers/queuestatus.py @@ -26,6 +26,7 @@ # (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 datetime import itertools from google.appengine.ext import webapp @@ -58,11 +59,29 @@ class QueueStatus(webapp.RequestHandler): def _fetch_statuses(self, queue, bot_id): statuses = queuestatus.QueueStatus.all() - statuses = statuses.filter("queue_name =", queue.name()) + statuses.filter("queue_name =", queue.name()) if bot_id: statuses.filter("bot_id =", bot_id) return statuses.order("-date").fetch(15) + def _fetch_last_message_matching(self, queue, bot_id, message): + statuses = queuestatus.QueueStatus.all() + statuses.filter("queue_name =", queue.name()) + if bot_id: + statuses.filter("bot_id =", bot_id) + statuses.filter("message =", message) + return statuses.order("-date").get() + + def _fetch_trailing_days_pass_count(self, queue, bot_id, days): + statuses = queuestatus.QueueStatus.all() + statuses.filter("queue_name =", queue.name()) + days_ago = datetime.datetime.now() - datetime.timedelta(days=days) + statuses.filter("date >", days_ago) + if bot_id: + statuses.filter("bot_id =", bot_id) + statuses.filter("message =", "Pass") + return statuses.count() + def _page_title(self, queue, bot_id): title = "%s Messages" % queue.display_name() if bot_id: @@ -82,5 +101,9 @@ class QueueStatus(webapp.RequestHandler): "work_item_rows": self._rows_for_work_items(queue), "status_groups": self._build_status_groups(statuses), "bot_id": bot_id, + "last_pass": self._fetch_last_message_matching(queue, bot_id, "Pass"), + "last_boot": self._fetch_last_message_matching(queue, bot_id, "Starting Queue"), + "trailing_month_pass_count": self._fetch_trailing_days_pass_count(queue, bot_id, 30), + "trailing_week_pass_count": self._fetch_trailing_days_pass_count(queue, bot_id, 7), } self.response.out.write(template.render("templates/queuestatus.html", template_values)) diff --git a/Tools/QueueStatusServer/index.yaml b/Tools/QueueStatusServer/index.yaml index 9724760..34eb72e 100644 --- a/Tools/QueueStatusServer/index.yaml +++ b/Tools/QueueStatusServer/index.yaml @@ -26,6 +26,27 @@ indexes: - kind: QueueStatus properties: - name: bot_id + - name: message + - name: queue_name + - name: date + direction: desc + +- kind: QueueStatus + properties: + - name: bot_id + - name: queue_name + - name: date + direction: desc + +- kind: QueueStatus + properties: + - name: message + - name: queue_name + - name: date + +- kind: QueueStatus + properties: + - name: message - name: queue_name - name: date direction: desc diff --git a/Tools/QueueStatusServer/model/activeworkitems.py b/Tools/QueueStatusServer/model/activeworkitems.py index ab5d7a6..023258a 100644 --- a/Tools/QueueStatusServer/model/activeworkitems.py +++ b/Tools/QueueStatusServer/model/activeworkitems.py @@ -61,6 +61,14 @@ class ActiveWorkItems(db.Model, QueuePropertyMixin): nonexpired_pairs = [pair for pair in self._item_time_pairs() if pair[0] != item_id] self._set_item_time_pairs(nonexpired_pairs) + @classmethod + def key_for_queue(cls, queue_name): + return "active-work-items-%s" % (queue_name) + + @classmethod + def lookup_by_queue(cls, queue_name): + return cls.get_or_insert(key_name=cls.key_for_queue(queue_name), queue_name=queue_name) + @staticmethod def _expire_item(key, item_id): active_work_items = db.get(key) diff --git a/Tools/QueueStatusServer/model/activeworkitems_unitest.py b/Tools/QueueStatusServer/model/activeworkitems_unittest.py index 6d915a1..b8c620a 100644 --- a/Tools/QueueStatusServer/model/activeworkitems_unitest.py +++ b/Tools/QueueStatusServer/model/activeworkitems_unittest.py @@ -28,15 +28,27 @@ import unittest from datetime import datetime +from google.appengine.ext import testbed from model.activeworkitems import ActiveWorkItems class ActiveWorkItemsTest(unittest.TestCase): + + def setUp(self): + self.testbed = testbed.Testbed() + self.testbed.activate() + self.testbed.init_datastore_v3_stub() + self.testbed.init_memcache_stub() + + def tearDown(self): + self.testbed.deactivate() + def test_basic(self): - items = ActiveWorkItems() + items = ActiveWorkItems.lookup_by_queue("test-queue") queued_items = [1, 2] - time = datetime.now() + # db.Model only stores dates to second resolution, so we use an explicit datetime without milliseconds. + time = datetime(2011, 4, 18, 18, 50, 44) self.assertEqual(items.next_item(queued_items, time), 1) self.assertEqual(items.next_item([1], time), None) self.assertEqual(items.next_item([], time), None) @@ -45,8 +57,8 @@ class ActiveWorkItemsTest(unittest.TestCase): self.assertEqual(items.time_for_item(2), None) items.expire_item(1) + # expire_item uses a transaction so it doesn't take effect on the current object. + self.assertEqual(items.time_for_item(1), time) + # If we look up the saved object, we see it's been updated. + items = ActiveWorkItems.lookup_by_queue("test-queue") self.assertEqual(items.time_for_item(1), None) - - -if __name__ == '__main__': - unittest.main() diff --git a/Tools/QueueStatusServer/model/queues.py b/Tools/QueueStatusServer/model/queues.py index 1d46f89..bd5e7ed 100644 --- a/Tools/QueueStatusServer/model/queues.py +++ b/Tools/QueueStatusServer/model/queues.py @@ -70,13 +70,11 @@ class Queue(object): return self._name def work_items(self): - key_name = "work-items-%s" % (self._name) - return WorkItems.get_or_insert(key_name=key_name, queue_name=self._name) + return WorkItems.lookup_by_queue(self._name) # FIXME: active_work_items is a bad name for this lock-table. def active_work_items(self): - key_name = "active-work-items-%s" % (self._name) - return ActiveWorkItems.get_or_insert(key_name=key_name, queue_name=self._name) + return ActiveWorkItems.lookup_by_queue(self._name) def _caplitalize_after_dash(self, string): return "-".join([word[0].upper() + word[1:] for word in string.split("-")]) diff --git a/Tools/QueueStatusServer/model/workitems.py b/Tools/QueueStatusServer/model/workitems.py index 772fc39..b74f5f5 100644 --- a/Tools/QueueStatusServer/model/workitems.py +++ b/Tools/QueueStatusServer/model/workitems.py @@ -36,6 +36,14 @@ class WorkItems(db.Model, QueuePropertyMixin): item_ids = db.ListProperty(int) date = db.DateTimeProperty(auto_now_add=True) + @classmethod + def key_for_queue(cls, queue_name): + return "work-items-%s" % (queue_name) + + @classmethod + def lookup_by_queue(cls, queue_name): + return cls.get_or_insert(key_name=cls.key_for_queue(queue_name), queue_name=queue_name) + def display_position_for_attachment(self, attachment_id): """Returns a 1-based index corresponding to the position of the attachment_id in the queue. If the attachment is diff --git a/Tools/QueueStatusServer/templates/queuestatus.html b/Tools/QueueStatusServer/templates/queuestatus.html index c68abf1..f5b4523 100644 --- a/Tools/QueueStatusServer/templates/queuestatus.html +++ b/Tools/QueueStatusServer/templates/queuestatus.html @@ -7,6 +7,22 @@ <body> <h1>{{ page_title }}</h1> +<h3>Summary</h3> +<div> +Last Pass: {{ last_pass.date|timesince }} ago +{% if not bot_id and last_pass.bot_id %} +by <a href="/queue-status/{{last_pass.queue_name}}/bots/{{last_pass.bot_id}}">{{ last_pass.bot_id }}</a> +{% endif %} +</div> +<div> +Last Boot: {{ last_boot.date|timesince }} ago +{% if not bot_id and last_boot.bot_id %} +by <a href="/queue-status/{{last_boot.queue_name}}/bots/{{last_boot.bot_id}}">{{ last_boot.bot_id }}</a> +{% endif %} +</div> +<div>7-day "Pass" count: {{ trailing_week_pass_count }}</div> +<div>30-day "Pass" count: {{ trailing_month_pass_count }}</div> + <h3>Recent Status</h3> <div class="status-details"> diff --git a/Tools/RebaselineQueueServer/app.yaml b/Tools/RebaselineQueueServer/app.yaml new file mode 100755 index 0000000..c425cfd --- /dev/null +++ b/Tools/RebaselineQueueServer/app.yaml @@ -0,0 +1,11 @@ +application: rebaseline-queue +version: 1 +runtime: python +api_version: 1 + +handlers: +- url: /static + static_dir: static + +- url: .* + script: main.py diff --git a/Tools/RebaselineQueueServer/handlers/__init__.py b/Tools/RebaselineQueueServer/handlers/__init__.py new file mode 100644 index 0000000..ef65bee --- /dev/null +++ b/Tools/RebaselineQueueServer/handlers/__init__.py @@ -0,0 +1 @@ +# Required for Python to search this directory for module files diff --git a/Tools/RebaselineQueueServer/handlers/builderqueue.py b/Tools/RebaselineQueueServer/handlers/builderqueue.py new file mode 100644 index 0000000..c84e07b --- /dev/null +++ b/Tools/RebaselineQueueServer/handlers/builderqueue.py @@ -0,0 +1,95 @@ +# Copyright (C) 2011 Google 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: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * 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. +# * Neither the name of Google Inc. 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 THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT +# OWNER OR 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. + +from urllib import unquote_plus + +from google.appengine.ext import webapp +from google.appengine.ext.webapp import template +from django.utils import simplejson + +from model.queueentry import QueueEntry + + +class QueueHandler(webapp.RequestHandler): + def get(self, builder_name): + self._get(unquote_plus(builder_name)) + + def post(self, builder_name): + self._post(unquote_plus(builder_name)) + + def _queued_test_names(self, builder_name): + return [entry.test for entry in QueueEntry.entries_for_builder(builder_name)] + + def _queue_list_url(self, builder_name): + return '/builder/%s/queue' % builder_name + + +class QueueEdit(QueueHandler): + def _get(self, builder_name): + test_names = self._queued_test_names(builder_name) + self.response.out.write( + template.render("templates/builder-queue-edit.html", { + 'builder_name': builder_name, + 'queued_test_names': simplejson.dumps(test_names), + })) + + +class QueueAdd(QueueHandler): + def _post(self, builder_name): + current_tests = set(self._queued_test_names(builder_name)) + tests = set(self.request.get_all('test')).difference(current_tests) + + for test in tests: + QueueEntry.add(builder_name, test) + + self.redirect(self._queue_list_url(builder_name)) + + +class QueueRemove(QueueHandler): + def _post(self, builder_name): + tests = self.request.get_all('test') + + for test in tests: + QueueEntry.remove(builder_name, test) + + self.redirect(self._queue_list_url(builder_name)) + + +class QueueHtml(QueueHandler): + def _get(self, builder_name): + self.response.out.write( + template.render("templates/builder-queue-list.html", { + 'builder_name': builder_name, + 'entries': QueueEntry.entries_for_builder(builder_name), + })) + + +class QueueJson(QueueHandler): + def _get(self, builder_name): + queue_json = {'tests': self._queued_test_names(builder_name)} + self.response.out.write(simplejson.dumps(queue_json)) diff --git a/Tools/RebaselineQueueServer/handlers/pages.py b/Tools/RebaselineQueueServer/handlers/pages.py new file mode 100644 index 0000000..8fcf2e3 --- /dev/null +++ b/Tools/RebaselineQueueServer/handlers/pages.py @@ -0,0 +1,47 @@ +# Copyright (C) 2011 Google 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: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * 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. +# * Neither the name of Google Inc. 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 THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT +# OWNER OR 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. + +from google.appengine.ext import webapp +from google.appengine.ext.webapp import template + +from model.queueentry import QueueEntry + + +class Home(webapp.RequestHandler): + def get(self): + builder_names = QueueEntry.builder_names() + self.response.out.write( + template.render("templates/home.html", { + 'builder_names': builder_names, + })) + + +class BuilderPicker(webapp.RequestHandler): + def get(self): + self.response.out.write( + template.render("templates/builder-picker.html", {})) diff --git a/Tools/RebaselineQueueServer/index.yaml b/Tools/RebaselineQueueServer/index.yaml new file mode 100755 index 0000000..a3b9e05 --- /dev/null +++ b/Tools/RebaselineQueueServer/index.yaml @@ -0,0 +1,11 @@ +indexes: + +# AUTOGENERATED + +# This index.yaml is automatically updated whenever the dev_appserver +# detects that a new type of query is run. If you want to manage the +# index.yaml file manually, remove the above marker line (the line +# saying "# AUTOGENERATED"). If you want to manage some indexes +# manually, move them above the marker line. The index.yaml file is +# automatically uploaded to the admin console when you next deploy +# your application using appcfg.py. diff --git a/Tools/RebaselineQueueServer/main.py b/Tools/RebaselineQueueServer/main.py new file mode 100755 index 0000000..4497d63 --- /dev/null +++ b/Tools/RebaselineQueueServer/main.py @@ -0,0 +1,56 @@ +# Copyright (C) 2011 Google 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: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * 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. +# * Neither the name of Google Inc. 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 THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT +# OWNER OR 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. + +# Request a modern Django +from google.appengine.dist import use_library +use_library('django', '1.2') + +from google.appengine.ext import webapp +from google.appengine.ext.webapp import util + +from handlers import pages +from handlers import builderqueue + + +def main(): + application = webapp.WSGIApplication([ + ('/', pages.Home), + ('/builder/picker', pages.BuilderPicker), + + # Queue CRUD operations + ('/builder/(.+)/queue/edit', builderqueue.QueueEdit), + ('/builder/(.+)/queue/add', builderqueue.QueueAdd), + ('/builder/(.+)/queue/remove', builderqueue.QueueRemove), + ('/builder/(.+)/queue', builderqueue.QueueHtml), + ('/builder/(.+)/queue/json', builderqueue.QueueJson), + ], + debug=True) + util.run_wsgi_app(application) + +if __name__ == '__main__': + main() diff --git a/Tools/RebaselineQueueServer/model/__init__.py b/Tools/RebaselineQueueServer/model/__init__.py new file mode 100644 index 0000000..ef65bee --- /dev/null +++ b/Tools/RebaselineQueueServer/model/__init__.py @@ -0,0 +1 @@ +# Required for Python to search this directory for module files diff --git a/Tools/RebaselineQueueServer/model/queueentry.py b/Tools/RebaselineQueueServer/model/queueentry.py new file mode 100644 index 0000000..6570fc0 --- /dev/null +++ b/Tools/RebaselineQueueServer/model/queueentry.py @@ -0,0 +1,63 @@ +# Copyright (C) 2011 Google 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: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * 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. +# * Neither the name of Google Inc. 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 THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT +# OWNER OR 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. + +from google.appengine.ext import db + + +class QueueEntry(db.Model): + test = db.StringProperty() + builder = db.StringProperty() + + @staticmethod + def add(builder_name, test): + entry = QueueEntry() + entry.builder = builder_name + entry.test = test + entry.put() + return entry + + @staticmethod + def remove(builder_name, test): + query = QueueEntry.all() + query = query.filter('builder =', builder_name).filter('test =', test) + for entry in query: + entry.delete() + + @staticmethod + def entries_for_builder(builder_name): + query = QueueEntry.all() + query = query.filter('builder =', builder_name) + return query + + @staticmethod + def builder_names(): + query = QueueEntry.all() + builder_names = set() + for entry in query: + builder_names.add(entry.builder) + return builder_names diff --git a/Tools/RebaselineQueueServer/static/builder-frame-empty.html b/Tools/RebaselineQueueServer/static/builder-frame-empty.html new file mode 100644 index 0000000..31b91bb --- /dev/null +++ b/Tools/RebaselineQueueServer/static/builder-frame-empty.html @@ -0,0 +1,10 @@ +<!DOCTYPE html> +<html> +<head> + <title>Rebaseline Queue</title> + <link rel="stylesheet" href="/static/styles.css" type="text/css"> +</head> +<body> +Select a group and then a builder to see tests that are currently failing on it (if any). +</body> +</html> diff --git a/Tools/RebaselineQueueServer/static/styles.css b/Tools/RebaselineQueueServer/static/styles.css new file mode 100644 index 0000000..a36ff35 --- /dev/null +++ b/Tools/RebaselineQueueServer/static/styles.css @@ -0,0 +1,71 @@ +body { + font-family: Helvetica, Arial, sans-serif; + font-size: 12px; +} + +h1 { + border-bottom: solid 1px #ccc; +} + +#builder-picker body, +#add-form body { + margin: 0; +} + +#builder-picker, +#builder-picker body { + height: 100%; +} + +#builder-picker body { + display: -webkit-box; + -webkit-box-orient: vertical; +} + +#builder-picker-controls { + padding: 0.5em; + border-bottom: solid 1px black; +} + +#builder-picker-controls select { + min-width: 10em; +} + +#builder-frame { + border: 0; + -webkit-box-flex: 1; + display: block; +} + +.status { + font-size: 16px; + text-align: center; + padding: 1em; +} + +.test-table { + border-collapse: collapse; +} + +.test-table caption { + font-size: 16px; + font-weight: bold; + background: #eee; + padding: .5em; +} + +.test-table th { + text-align: left; + border-bottom: solid 1px #ccc; + background: #eee; + min-width: 8em; +} + +.test-table tbody tr:hover { + background: #ffa; +} + +.test-table .submit-row { + text-align: right; + padding: 1em 0; +} diff --git a/Tools/RebaselineQueueServer/templates/builder-picker.html b/Tools/RebaselineQueueServer/templates/builder-picker.html new file mode 100644 index 0000000..1068c04 --- /dev/null +++ b/Tools/RebaselineQueueServer/templates/builder-picker.html @@ -0,0 +1,74 @@ +<!DOCTYPE html> +<html id="builder-picker"> +<head> + <title>Rebaseline Queue: Builders</title> + <script src="http://test-results.appspot.com/dashboards/builders.js"></script> + <link rel="stylesheet" href="/static/styles.css" type="text/css"> +</head> +<body> + +<div id="builder-picker-controls"> + <label for="builder-group">Group:</label> + <select id="builder-group"> + <option disabled></option> + </select> + + <label for="builder">Builder:</label> + <select id="builder"> + <option disabled></option> + </select> +</div> + +<iframe src="/static/builder-frame-empty.html" id="builder-frame"></iframe> + +<script> +function init() +{ + var builderGroupMenu = document.getElementById('builder-group'); + builderGroupMenu.addEventListener( + 'change', handleBuilderGroupSelected, false); + + var builderMenu = document.getElementById('builder'); + builderMenu.addEventListener( + 'change', handleBuilderSelected, false); + + for (var builderGroupName in LAYOUT_TESTS_BUILDER_GROUPS) { + var builderGroupOption = document.createElement('option'); + builderGroupOption.textContent = builderGroupOption.value = + builderGroupName; + builderGroupMenu.appendChild(builderGroupOption); + } +} + +function handleBuilderGroupSelected() +{ + var builderGroupMenu = document.getElementById('builder-group'); + var builderGroupName = + builderGroupMenu.options[builderGroupMenu.selectedIndex].value; + var builderGroup = LAYOUT_TESTS_BUILDER_GROUPS[builderGroupName]; + + var builderMenu = document.getElementById('builder'); + while (builderMenu.options[1]) { + builderMenu.removeChild(builderMenu.options[1]); + } + + for (var builderName in builderGroup.builders) { + var builderOption = document.createElement('option'); + builderOption.textContent = builderOption.value = builderName; + builderMenu.appendChild(builderOption); + } +} + +function handleBuilderSelected() +{ + var builderMenu = document.getElementById('builder'); + var builderName = builderMenu.options[builderMenu.selectedIndex].value; + document.getElementById('builder-frame').src = + '/builder/' + builderName + '/queue/edit'; +} + +init(); +</script> + +</body> +</html> diff --git a/Tools/RebaselineQueueServer/templates/builder-queue-edit.html b/Tools/RebaselineQueueServer/templates/builder-queue-edit.html new file mode 100644 index 0000000..21a0f02 --- /dev/null +++ b/Tools/RebaselineQueueServer/templates/builder-queue-edit.html @@ -0,0 +1,176 @@ +<!DOCTYPE html> +<html id="add-form"> +<head> + <title>Rebaseline Queue: Edit</title> + <script src="http://test-results.appspot.com/dashboards/builders.js"></script> + <link rel="stylesheet" href="/static/styles.css" type="text/css"> +</head> +<body"> + +<div id="loading-indicator" class="status">Loading...</div> + +<form method="POST" id="form-template" style="display: none"> + <table class="test-table"> + <caption></caption> + <thead> + <th>Test</th> + <th>Expected</th> + <th>Actual</th> + <th>Results</th> + </thead> + <tbody></tbody> + <tbody> + <tr> + <td colspan="4" class="submit-row"> + <input type="submit" value=""> + </td> + </tr> + </tbody> + </table> +</form> + +<script> +var TEST_RESULTS_SERVER = 'http://test-results.appspot.com/'; +var BUILDER_TO_GROUP = {}; +for (var builderGroupName in LAYOUT_TESTS_BUILDER_GROUPS) { + for (var builderName in LAYOUT_TESTS_BUILDER_GROUPS[builderGroupName]) { + BUILDER_TO_GROUP[builderName] = builderGroupName; + } +} + +// Extract template parameters +var builderName = '{{ builder_name|escapejs }}'; +var queuedTestNames = {{ queued_test_names|safe }}; + +function init() +{ + var builderMaster = BUILDER_TO_MASTER[builderName]; + var resultsUrl = TEST_RESULTS_SERVER + 'testfile?builder=' + builderName + + '&master=' + builderMaster.name + + '&testtype=layout-tests&name=full_results.json'; + + var script = document.createElement('script'); + script.src = resultsUrl; + document.getElementsByTagName('head')[0].appendChild(script); +} + +function ADD_RESULTS(results) +{ + var builderGroupName = BUILDER_TO_GROUP[builderName]; + + var tests = results.tests; + var failingTests = []; + var queuedTests = []; + for (var test in tests) { + var testResults = tests[test]; + if (testResults.actual == testResults.expected || + testResults.expected.split(' ').indexOf(testResults.actual) != -1 || + testResults.actual == 'SKIP' || + testResults.actual.indexOf('PASS') != -1 || + (testResults.actual != 'PASS' && testResults.expected.indexOf('FAIL') != -1)) { + continue; + } + + testResults.name = test; + + if (queuedTestNames.indexOf(test) != -1) { + queuedTests.push(testResults); + queuedTestNames.splice(queuedTestNames.indexOf(test), 1); + } else { + failingTests.push(testResults); + } + } + + // If we have remaining queued tests that are currently not failing, + // synthesize results for them. + queuedTestNames.forEach(function(queuedTestName) { + queuedTests.push({ + name: queuedTestName, + actual: 'UNKNOWN', + expected: 'UNKNOWN' + }); + }); + + document.getElementById('loading-indicator').style.display = 'none'; + + renderTestResults( + failingTests, + 'add', + 'Failing tests', + 'Add to rebaseline queue', + 'No failing tests.'); + renderTestResults( + queuedTests, + 'remove', + 'Queued tests', + 'Remove from rebaseline queue', + 'No queued tests.'); +} + +function renderTestResults(testResults, formAction, title, submitLabel, emptyMessage) +{ + if (testResults.length == 0) { + var emptyNode = document.createElement('div'); + emptyNode.className = 'status'; + emptyNode.textContent = emptyMessage; + document.body.appendChild(emptyNode); + return; + } + + var form = document.getElementById('form-template').cloneNode(true); + form.action = '/builder/' + builderName + '/queue/' + formAction; + form.style.display = ''; + document.body.appendChild(form); + + var testsTable = form.querySelector('.test-table'); + testsTable.querySelector('caption').textContent = title; + testsTable.querySelector('input[type=submit]').value = submitLabel; + + testResults.sort(function(a, b) { + return a.name < b.name ? -1 : (a.name > b.name ? 1 : 0); + }); + + testResults.forEach(function(result) { + var testRow = document.createElement('tr'); + + var testCell = document.createElement('td'); + testRow.appendChild(testCell); + var testCheckbox = document.createElement('input'); + testCheckbox.type = 'checkbox'; + testCheckbox.name = 'test'; + testCheckbox.value = result.name; + testCheckbox.id = result.name; + testCell.appendChild(testCheckbox); + + var testName = document.createElement('label'); + testName.textContent = result.name; + testName.setAttribute('for', result.name); + testCell.appendChild(testName); + + var expectedCell = document.createElement('td'); + testRow.appendChild(expectedCell); + expectedCell.textContent = result.expected; + + var actualCell = document.createElement('td'); + testRow.appendChild(actualCell); + actualCell.textContent = result.actual; + + var resultsCell = document.createElement('td'); + testRow.appendChild(resultsCell); + var resultsLink = document.createElement('a'); + resultsLink.target = '_blank'; + resultsLink.href = TEST_RESULTS_SERVER + + 'dashboards/flakiness_dashboard.html#tests=' + result.name + + '&group=' + builderGroupName; + resultsLink.textContent = 'Flakiness dashboard'; + resultsCell.appendChild(resultsLink); + + testsTable.tBodies[0].appendChild(testRow); + }); +} + +init(); +</script> + +</body> +</html> diff --git a/Tools/RebaselineQueueServer/templates/builder-queue-list.html b/Tools/RebaselineQueueServer/templates/builder-queue-list.html new file mode 100644 index 0000000..79fa02a --- /dev/null +++ b/Tools/RebaselineQueueServer/templates/builder-queue-list.html @@ -0,0 +1,23 @@ +<!DOCTYPE html> +<html> +<head> + <title>{{ builder_name|escape }} Queue</title> + <link rel="stylesheet" href="/static/styles.css" type="text/css"> +</head> +<body> + +<h1>Queue: {{ builder_name|escape }}</h1> + +<ol> +{% for entry in entries %} + <li> + {{ entry.test|escape }} + </li> +{% empty %} + No tests found in queue. +{% endfor %} +</ol> + +<a href="/builder/{{ builder_name|escape }}/queue/edit">Edit queue</a> +</body> +</html> diff --git a/Tools/RebaselineQueueServer/templates/home.html b/Tools/RebaselineQueueServer/templates/home.html new file mode 100644 index 0000000..c6a16ff --- /dev/null +++ b/Tools/RebaselineQueueServer/templates/home.html @@ -0,0 +1,28 @@ +<!DOCTYPE html> +<html> +<head> + <title>Rebaseline Queue</title> + <link rel="stylesheet" href="/static/styles.css" type="text/css"> +</head> +<body> + +<h1>Rebaseline Queue</h1> + +<ul> + <li><a href="/builder/picker">Browse and enqueue failing tests on builders</a></li> + <li> + Builders with enqueued tests: + <ul> +{% for builder_name in builder_names %} + <li> + <a href="/builder/{{ builder_name|escape }}/queue">{{ builder_name|escape }}</a> + </li> +{% empty %} + None +{% endfor %} + </ul> + </li> +</ul> + +</body> +</html> diff --git a/Tools/Scripts/VCSUtils.pm b/Tools/Scripts/VCSUtils.pm index a05a75d..8353f25 100644 --- a/Tools/Scripts/VCSUtils.pm +++ b/Tools/Scripts/VCSUtils.pm @@ -1,6 +1,6 @@ # Copyright (C) 2007, 2008, 2009 Apple Inc. All rights reserved. # Copyright (C) 2009, 2010 Chris Jerdonek (chris.jerdonek@gmail.com) -# Copyright (C) Research In Motion Limited 2010. All rights reserved. +# Copyright (C) 2010, 2011 Research In Motion Limited. All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions @@ -68,6 +68,7 @@ BEGIN { &makeFilePathRelative &mergeChangeLogs &normalizePath + &parseFirstEOL &parsePatch &pathRelativeToSVNRepositoryRootForPath &prepareParsedPatch @@ -97,6 +98,7 @@ my $svnVersion; # Project time zone for Cupertino, CA, US my $changeLogTimeZone = "PST8PDT"; +my $chunkRangeRegEx = qr#^\@\@ -(\d+),(\d+) \+\d+,(\d+) \@\@$#; # e.g. @@ -2,6 +2,18 @@ my $gitDiffStartRegEx = qr#^diff --git (\w/)?(.+) (\w/)?([^\r\n]+)#; my $svnDiffStartRegEx = qr#^Index: ([^\r\n]+)#; my $svnPropertiesStartRegEx = qr#^Property changes on: ([^\r\n]+)#; # $1 is normally the same as the index path. @@ -449,6 +451,40 @@ sub removeEOL($) return $line; } +sub parseFirstEOL($) +{ + my ($fileHandle) = @_; + + # Make input record separator the new-line character to simplify regex matching below. + my $savedInputRecordSeparator = $INPUT_RECORD_SEPARATOR; + $INPUT_RECORD_SEPARATOR = "\n"; + my $firstLine = <$fileHandle>; + $INPUT_RECORD_SEPARATOR = $savedInputRecordSeparator; + + return unless defined($firstLine); + + my $eol; + if ($firstLine =~ /\r\n/) { + $eol = "\r\n"; + } elsif ($firstLine =~ /\r/) { + $eol = "\r"; + } elsif ($firstLine =~ /\n/) { + $eol = "\n"; + } + return $eol; +} + +sub firstEOLInFile($) +{ + my ($file) = @_; + my $eol; + if (open(FILE, $file)) { + $eol = parseFirstEOL(*FILE); + close(FILE); + } + return $eol; +} + sub svnStatus($) { my ($fullPath) = @_; @@ -822,23 +858,30 @@ sub parseDiffHeader($$) # $fileHandle: a file handle advanced to the first line of the next # header block. Leading junk is okay. # $line: the line last read from $fileHandle. +# $optionsHashRef: a hash reference representing optional options to use +# when processing a diff. +# shouldNotUseIndexPathEOL: whether to use the line endings in the diff instead +# instead of the line endings in the target file; the +# value of 1 if svnConvertedText should use the line +# endings in the diff. # # Returns ($diffHashRefs, $lastReadLine): # $diffHashRefs: A reference to an array of references to %diffHash hashes. # See the %diffHash documentation above. # $lastReadLine: the line last read from $fileHandle -sub parseDiff($$) +sub parseDiff($$;$) { # FIXME: Adjust this method so that it dies if the first line does not # match the start of a diff. This will require a change to # parsePatch() so that parsePatch() skips over leading junk. - my ($fileHandle, $line) = @_; + my ($fileHandle, $line, $optionsHashRef) = @_; my $headerStartRegEx = $svnDiffStartRegEx; # SVN-style header for the default my $headerHashRef; # Last header found, as returned by parseDiffHeader(). my $svnPropertiesHashRef; # Last SVN properties diff found, as returned by parseSvnDiffProperties(). my $svnText; + my $indexPathEOL; while (defined($line)) { if (!$headerHashRef && ($line =~ $gitDiffStartRegEx)) { # Then assume all diffs in the patch are Git-formatted. This @@ -861,6 +904,11 @@ sub parseDiff($$) } if ($line !~ $headerStartRegEx) { # Then we are in the body of the diff. + if ($indexPathEOL && $line !~ /$chunkRangeRegEx/) { + # The chunk range is part of the body of the diff, but its line endings should't be + # modified or patch(1) will complain. So, we only modify non-chunk range lines. + $line =~ s/\r\n|\r|\n/$indexPathEOL/g; + } $svnText .= $line; $line = <$fileHandle>; next; @@ -873,6 +921,9 @@ sub parseDiff($$) } ($headerHashRef, $line) = parseDiffHeader($fileHandle, $line); + if (!$optionsHashRef || !$optionsHashRef->{shouldNotUseIndexPathEOL}) { + $indexPathEOL = firstEOLInFile($headerHashRef->{indexPath}) if !$headerHashRef->{isNew} && !$headerHashRef->{isBinary}; + } $svnText .= $headerHashRef->{svnConvertedText}; } @@ -1167,13 +1218,19 @@ sub parseSvnPropertyValue($$) # Args: # $fileHandle: A file handle to the patch file that has not yet been # read from. +# $optionsHashRef: a hash reference representing optional options to use +# when processing a diff. +# shouldNotUseIndexPathEOL: whether to use the line endings in the diff instead +# instead of the line endings in the target file; the +# value of 1 if svnConvertedText should use the line +# endings in the diff. # # Returns: # @diffHashRefs: an array of diff hash references. # See the %diffHash documentation above. -sub parsePatch($) +sub parsePatch($;$) { - my ($fileHandle) = @_; + my ($fileHandle, $optionsHashRef) = @_; my $newDiffHashRefs; my @diffHashRefs; # return value @@ -1182,7 +1239,7 @@ sub parsePatch($) while (defined($line)) { # Otherwise, at EOF. - ($newDiffHashRefs, $line) = parseDiff($fileHandle, $line); + ($newDiffHashRefs, $line) = parseDiff($fileHandle, $line, $optionsHashRef); push @diffHashRefs, @$newDiffHashRefs; } @@ -1440,7 +1497,6 @@ sub fixChangeLogPatch($) $deletedLineCount += $dateStartIndex - $chunkStartIndex; # Update the initial chunk range. - my $chunkRangeRegEx = '^\@\@ -(\d+),(\d+) \+\d+,(\d+) \@\@$'; # e.g. @@ -2,6 +2,18 @@ if ($lines[$chunkStartIndex - 1] !~ /$chunkRangeRegEx/) { # FIXME: Handle errors differently from ChangeLog files that # are okay but should not be altered. That way we can find out diff --git a/Tools/Scripts/build-webkit b/Tools/Scripts/build-webkit index 8ff638d..1b4743e 100755 --- a/Tools/Scripts/build-webkit +++ b/Tools/Scripts/build-webkit @@ -96,7 +96,9 @@ my ( $notificationsSupport, $offlineWebApplicationSupport, $orientationEventsSupport, + $pageVisibilityApiSupport, $progressTagSupport, + $quotaSupport, $registerProtocolHandlerSupport, $sharedWorkersSupport, $svgSupport, @@ -225,9 +227,15 @@ my @features = ( { option => "orientation-events", desc => "Toggle Orientation Events support", define => "ENABLE_ORIENTATION_EVENTS", default => 0, value => \$orientationEventsSupport }, + { option => "page-visibility-api", desc => "Page Visibility API support", + define => "ENABLE_PAGE_VISIBILITY_API", default => 0, value => \$pageVisibilityApiSupport }, + { option => "progress-tag", desc => "Progress Tag support", define => "ENABLE_PROGRESS_TAG", default => 1, value => \$progressTagSupport }, + { option => "quota", desc => "Toggle Quota support", + define => "ENABLE_QUOTA", default => 0, value => \$quotaSupport }, + { option => "register-protocol-handler", desc => "Register Protocol Handler support", define => "ENABLE_REGISTER_PROTOCOL_HANDLER", default => 0, value => \$registerProtocolHandlerSupport }, @@ -354,6 +362,7 @@ Usage: $programName [options] [options to pass to build system] --install-headers=<path> Set installation path for the headers (Qt only) --install-libs=<path> Set installation path for the libraries (Qt only) --v8 Use V8 as JavaScript engine (Qt only) + -2 build WebKit2 (Qt only) --prefix=<path> Set installation prefix to the given path (Gtk/Efl only) --makeargs=<arguments> Optional Makefile flags @@ -414,13 +423,16 @@ sub unlinkZeroFiles() # Check that all the project directories are there. my @projects = ("Source/JavaScriptCore", "Source/WebCore", "Source/WebKit"); -my @otherDirs = ("WebKitLibraries"); -for my $dir (@projects, @otherDirs) { +for my $dir (@projects) { if (! -d $dir) { die "Error: No $dir directory found. Please do a fresh checkout.\n"; } } +if (!isQt() && !-d "WebKitLibraries") { + die "Error: No WebKitLibraries directory found. Please do a fresh checkout.\n"; +} + # Generate the generate project files from .gyp files if ($useGYP) { system("perl", "Tools/Scripts/generate-project-files") == 0 or die "Failed to run generate-project-files"; @@ -500,11 +512,16 @@ if (isGtk()) { # Copy WebKitSupportLibrary to the correct location in WebKitLibraries so it can be found. # Will fail if WebKitSupportLibrary.zip is not in source root. (system("perl Tools/Scripts/update-webkit-support-libs") == 0) or die; + # Update Cairo Dependancies. + if (isWinCairo()) { + (system("perl Tools/Scripts/update-webkit-wincairo-libs") == 0) or die; + } } elsif (isQt()) { - @options = @ARGV; push @options, "--install-headers=" . $installHeaders if defined($installHeaders); push @options, "--install-libs=" . $installLibs if defined($installLibs); push @options, "--makeargs=" . $makeArgs if $makeArgs; + push @options, "--qmakearg=CONFIG+=webkit2" if isWK2(); + @options = (@ARGV, @options); foreach (@features) { push @options, "DEFINES+=$_->{define}=${$_->{value}}" if ${$_->{value}} != $_->{default}; diff --git a/Tools/Scripts/do-webcore-rename b/Tools/Scripts/do-webcore-rename index da08cf7..4829f39 100755 --- a/Tools/Scripts/do-webcore-rename +++ b/Tools/Scripts/do-webcore-rename @@ -97,7 +97,7 @@ sub wanted my $isDOMTypeRename = 0; my %renames = ( # Renames go here in the form of: - "DocLoader" => "CachedResourceLoader", + "MediaControls" => "MediaControlRootElement", ); my %renamesContemplatedForTheFuture = ( diff --git a/Tools/Scripts/extract-localizable-strings b/Tools/Scripts/extract-localizable-strings index 116f11f..dae60c2 100755 --- a/Tools/Scripts/extract-localizable-strings +++ b/Tools/Scripts/extract-localizable-strings @@ -107,7 +107,7 @@ for my $dir (@directoriesToSkip) { my @files = ( split "\n", `find $quotedDirectoriesString \\( -name "*.h" -o -name "*.m" -o -name "*.mm" -o -name "*.c" -o -name "*.cpp" \\)` ); for my $file (sort @files) { - next if $file =~ /\/\w+LocalizableStrings\w*\.h$/; + next if $file =~ /\/\w+LocalizableStrings\w*\.h$/ || $file =~ /\/LocalizedStrings\.h$/; $file =~ s-^./--; @@ -169,7 +169,7 @@ handleString: # FIXME: Validate UTF-8 here? $UIString = $string; $expected = ","; - } elsif (($macro =~ /UI_STRING_KEY(_INTERNAL)?$/) and !defined $key) { + } elsif (($macro =~ /(WEB_)?UI_STRING_KEY(_INTERNAL)?$/) and !defined $key) { # FIXME: Validate UTF-8 here? $key = $string; $expected = ","; @@ -228,7 +228,7 @@ handleString: $sawError = 1; $expected = ""; } - if ($token =~ /UI_STRING(_KEY)?(_INTERNAL)?$/) { + if ($token =~ /(WEB_)?UI_STRING(_KEY)?(_INTERNAL)?$/) { $expected = "("; $macro = $token; $UIString = undef; diff --git a/Tools/Scripts/gdb-safari b/Tools/Scripts/gdb-safari index 9776212..0c55bd3 100755 --- a/Tools/Scripts/gdb-safari +++ b/Tools/Scripts/gdb-safari @@ -50,4 +50,4 @@ $ENV{WEBKIT_UNSET_DYLD_FRAMEWORK_PATH} = 'YES'; print "Starting Safari under gdb with DYLD_FRAMEWORK_PATH set to point to built WebKit in $productDir.\n"; my @architectureFlags = ("-arch", architecture()) if !isTiger(); -exec $gdbPath, @architectureFlags, $safariPath or die; +exec $gdbPath, @architectureFlags, "--arg", $safariPath, @ARGV or die; diff --git a/Tools/Scripts/old-run-webkit-tests b/Tools/Scripts/old-run-webkit-tests index fe9bdd0..333777e 100755 --- a/Tools/Scripts/old-run-webkit-tests +++ b/Tools/Scripts/old-run-webkit-tests @@ -105,6 +105,7 @@ sub openWebSocketServerIfNeeded(); sub pathcmp($$); sub printFailureMessageForTest($$); sub processIgnoreTests($$); +sub readChecksumFromPng($); sub readFromDumpToolWithTimer(**); sub readSkippedFiles($); sub recordActualResultsAndDiff($$); @@ -125,6 +126,7 @@ sub writeToFile($$); # Argument handling my $addPlatformExceptions = 0; +my @additionalPlatformDirectories = (); my $complexText = 0; my $exitAfterNFailures = 0; my $exitAfterNCrashesOrTimeouts = 0; @@ -275,6 +277,8 @@ my $sampleDefault = $runSample ? "run" : "do not run"; my $usage = <<EOF; Usage: $programName [options] [testdir|testpath ...] --add-platform-exceptions Put new results for non-platform-specific failing tests into the platform-specific results directory + --additional-platform-directory path/to/directory + Look in the specified directory before looking in any of the default platform-specific directories --complex-text Use the complex text code path for all text (Mac OS X and Windows only) -c|--configuration config Set DumpRenderTree build configuration -g|--guard-malloc Enable malloc guard @@ -323,6 +327,7 @@ setConfiguration(); my $getOptionsResult = GetOptions( 'add-platform-exceptions' => \$addPlatformExceptions, + 'additional-platform-directory=s' => \@additionalPlatformDirectories, 'complex-text' => \$complexText, 'exit-after-n-failures=i' => \$exitAfterNFailures, 'exit-after-n-crashes-or-timeouts=i' => \$exitAfterNCrashesOrTimeouts, @@ -426,6 +431,7 @@ my $dumpToolName = $useWebKitTestRunner ? "WebKitTestRunner" : "DumpRenderTree"; if (isAppleWinWebKit()) { $dumpToolName .= "_debug" if configurationForVisualStudio() eq "Debug_All"; + $dumpToolName .= "_debug" if configurationForVisualStudio() eq "Debug_Cairo_CFLite"; $dumpToolName .= $Config{_exe}; } my $dumpTool = File::Spec->catfile($productDir, $dumpToolName); @@ -433,6 +439,7 @@ die "can't find executable $dumpToolName (looked in $productDir)\n" unless -x $d my $imageDiffTool = "$productDir/ImageDiff"; $imageDiffTool .= "_debug" if isCygwin() && configurationForVisualStudio() eq "Debug_All"; +$imageDiffTool .= "_debug" if isCygwin() && configurationForVisualStudio() eq "Debug_Cairo_CFLite"; die "can't find executable $imageDiffTool (looked in $productDir)\n" if $pixelTests && !-x $imageDiffTool; checkFrameworks() unless isCygwin(); @@ -556,6 +563,7 @@ if (!$hasAcceleratedCompositing) { $ignoredFiles{'media/controls-drag-timebar.html'} = 1; $ignoredFiles{'media/controls-strict.html'} = 1; $ignoredFiles{'media/controls-styling.html'} = 1; + $ignoredFiles{'media/controls-without-preload.html'} = 1; $ignoredFiles{'media/video-controls-rendering.html'} = 1; $ignoredFiles{'media/video-display-toggle.html'} = 1; $ignoredFiles{'media/video-no-audio.html'} = 1; @@ -599,6 +607,12 @@ if (!checkWebCoreFeatureSupport("XHTMLMP", 0)) { $ignoredDirectories{'fast/xhtmlmp'} = 1; } +if (isAppleMacWebKit() && $platform ne "mac-wk2" && osXVersion()->{minor} >= 6 && architecture() =~ /x86_64/) { + # This test relies on executing JavaScript during NPP_Destroy, which isn't supported with + # out-of-process plugins in WebKit1. See <http://webkit.org/b/58077>. + $ignoredFiles{'plugins/npp-set-window-called-during-destruction.html'} = 1; +} + processIgnoreTests(join(',', @ignoreTests), "ignore-tests") if @ignoreTests; if (!$ignoreSkipped) { if (!$skippedOnly || @ARGV == 0) { @@ -679,6 +693,9 @@ for (my $i = 1; $i < $iterations; $i++) { push(@tests, @originalTests); } +my $absTestResultsDirectory = resolveAndMakeTestResultsDirectory(); +open my $tests_run_fh, '>', "$absTestResultsDirectory/tests_run.txt" or die $!; + for my $test (@tests) { my $newDumpTool = not $isDumpToolOpen; openDumpTool(); @@ -729,6 +746,8 @@ for my $test (@tests) { my $startTime = time if $report10Slowest; + print $tests_run_fh "$testDirectory/$test\n"; + # Try to read expected hash file for pixel tests my $suffixExpectedHash = ""; if ($pixelTests && !$resetResults) { @@ -740,6 +759,8 @@ for my $test (@tests) { # Format expected hash into a suffix string that is appended to the path / URL passed to DRT $suffixExpectedHash = "'$expectedHash"; + } elsif (my $expectedHash = readChecksumFromPng(File::Spec->catfile($expectedPixelDir, "$base-$expectedTag.png"))) { + $suffixExpectedHash = "'$expectedHash"; } } @@ -1075,6 +1096,8 @@ for my $test (@tests) { last if stopRunningTestsEarlyIfNeeded(); } +close($tests_run_fh); + my $totalTestingTime = time - $overallStartTime; my $waitTime = getWaitTime(); if ($waitTime > 0.1) { @@ -1157,6 +1180,9 @@ print HTML htmlForResultsSection(@{$tests{webProcessCrash}}, "Tests that caused print HTML htmlForResultsSection(@{$tests{error}}, "Tests that had stderr output", \&linksForErrorTest); print HTML htmlForResultsSection(@{$tests{new}}, "Tests that had no expected results (probably new)", \&linksForNewTest); +print HTML "<p>httpd access log: <a href=\"access_log.txt\">access_log.txt</a></p>\n"; +print HTML "<p>httpd error log: <a href=\"error_log.txt\">error_log.txt</a></p>\n"; + print HTML "</body>\n"; print HTML "</html>\n"; close HTML; @@ -1255,12 +1281,6 @@ sub countAndPrintLeaks($$$) ); } - if (isDarwin() && !isTiger() && !isLeopard() && !isSnowLeopard()) { - push @callStacksToExclude, ( - "CGGradientCreateWithColorComponents", # leak in CoreGraphics, <rdar://problem/7888492> - ); - } - my $leaksTool = sourceDir() . "/Tools/Scripts/run-leaks"; my $excludeString = "--exclude-callstack '" . (join "' --exclude-callstack '", @callStacksToExclude) . "'"; $excludeString .= " --exclude-type '" . (join "' --exclude-type '", @typesToExclude) . "'" if @typesToExclude; @@ -2112,13 +2132,13 @@ sub recordActualResultsAndDiff($$) mkpath(dirname($actualResultsPath)); writeToFile("$actualResultsPath", $actualResults); - if (-f $expectedResultPath) { - copy("$expectedResultPath", "$copiedExpectedResultsPath"); - } else { - open EMPTY, ">$copiedExpectedResultsPath"; - close EMPTY; + # We don't need diff and pretty diff for tests without expected file. + if ( !-f $expectedResultPath) { + return; } + copy("$expectedResultPath", "$copiedExpectedResultsPath"); + my $diffOuputBasePath = File::Spec->catfile($testResultsDirectory, $base); my $diffOutputPath = "$diffOuputBasePath-$diffsTag.txt"; system "diff -u \"$copiedExpectedResultsPath\" \"$actualResultsPath\" > \"$diffOutputPath\""; @@ -2165,6 +2185,8 @@ sub buildPlatformResultHierarchy() push(@hierarchy, $scoped) if (-d $scoped); } + unshift @hierarchy, grep { -d $_ } @additionalPlatformDirectories; + return @hierarchy; } @@ -2457,6 +2479,15 @@ sub readSkippedFiles($) } } +sub readChecksumFromPng($) +{ + my ($path) = @_; + my $data; + if (open(PNGFILE, $path) && read(PNGFILE, $data, 2048) && $data =~ /tEXtchecksum\0([a-fA-F0-9]{32})/) { + return $1; + } +} + my @testsFound; sub isUsedInReftest @@ -2668,10 +2699,13 @@ sub setUpWindowsCrashLogSaving() my $ntsdPath = File::Spec->catfile(toCygwinPath($ENV{PROGRAMFILES}), "Debugging Tools for Windows (x86)", "ntsd.exe"); unless (-f $ntsdPath) { - $ntsdPath = File::Spec->catfile(toCygwinPath($ENV{SYSTEMROOT}), "system32", "ntsd.exe"); + $ntsdPath = File::Spec->catfile(toCygwinPath($ENV{ProgramW6432}), "Debugging Tools for Windows (x64)", "ntsd.exe"); unless (-f $ntsdPath) { - print STDERR "Can't find ntsd.exe. Crash logs will not be saved.\nSee <http://trac.webkit.org/wiki/BuildingOnWindows#GettingCrashLogs>.\n"; - return; + $ntsdPath = File::Spec->catfile(toCygwinPath($ENV{SYSTEMROOT}), "system32", "ntsd.exe"); + unless (-f $ntsdPath) { + print STDERR "Can't find ntsd.exe. Crash logs will not be saved.\nSee <http://trac.webkit.org/wiki/BuildingOnWindows#GettingCrashLogs>.\n"; + return; + } } } diff --git a/Tools/Scripts/prepare-ChangeLog b/Tools/Scripts/prepare-ChangeLog index a4b3d6b..e6fef40 100755 --- a/Tools/Scripts/prepare-ChangeLog +++ b/Tools/Scripts/prepare-ChangeLog @@ -140,6 +140,7 @@ if (!$parseOptionsResult || $showHelp) { print STDERR " -o|--open Open ChangeLogs in an editor when done\n"; print STDERR " --[no-]update Update ChangeLogs from svn before adding entry (default: update)\n"; print STDERR " --[no-]write Write ChangeLogs to disk (otherwise send new entries to stdout) (default: write)\n"; + print STDERR " --email= Specify the email address to be used in the patch\n"; exit 1; } diff --git a/Tools/Scripts/run-iexploder-tests b/Tools/Scripts/run-iexploder-tests index 97e3630..cb696a2 100755 --- a/Tools/Scripts/run-iexploder-tests +++ b/Tools/Scripts/run-iexploder-tests @@ -114,7 +114,6 @@ sub configureAndOpenHTTPDIfNeeded() { return if $isHttpdOpen; mkdir $iExploderTestDirectory; - my $httpdPath = getHTTPDPath(); my $webkitDirectory = getcwd(); my $testDirectory = $webkitDirectory . "/LayoutTests"; my $iExploderDirectory = $webkitDirectory . "/Tools/iExploder/iExploder-1.3.2"; diff --git a/Tools/Scripts/update-webkit b/Tools/Scripts/update-webkit index 5c132ae..6a7b9f7 100755 --- a/Tools/Scripts/update-webkit +++ b/Tools/Scripts/update-webkit @@ -2,6 +2,7 @@ # Copyright (C) 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved. # Copyright (C) 2009 Google Inc. All rights reserved. +# Copyright (C) 2011 Brent Fulgham. All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions @@ -49,6 +50,8 @@ my $useGYP = 0; determineIsChromium(); +determineIsWinCairo(); + chdirWebKit(); my $getOptionsResult = GetOptions( @@ -64,6 +67,7 @@ Usage: @{[ basename($0) ]} [options] -h|--help show the help message -q|--quiet pass -q to svn update for quiet updates --gyp generate project files from gyp after update + --wincairo also update dependencies of the WinCairo port __END__ exit 1; } @@ -96,6 +100,9 @@ if (-d "../Internal") { system("perl", "Tools/Scripts/update-webkit-chromium") == 0 or die $!; } elsif (isAppleWinWebKit()) { system("perl", "Tools/Scripts/update-webkit-auxiliary-libs") == 0 or die; + if (isWinCairo()) { + system("perl", "Tools/Scripts/update-webkit-wincairo-libs") == 0 or die; + } } setupAppleWinEnv() if isAppleWinWebKit(); diff --git a/Tools/Scripts/update-webkit-auxiliary-libs b/Tools/Scripts/update-webkit-auxiliary-libs index 9a6b20f..d301938 100755 --- a/Tools/Scripts/update-webkit-auxiliary-libs +++ b/Tools/Scripts/update-webkit-auxiliary-libs @@ -30,106 +30,11 @@ use strict; use warnings; - -use File::Find; -use File::Spec; -use File::Temp (); use FindBin; -use HTTP::Date qw(str2time); -use POSIX; -use lib $FindBin::Bin; -use webkitdirs; - -sub lastModifiedToUnixTime($); - -# Time in seconds that the new zip file must be newer than the old for us to -# consider them to be different. If the difference in modification time is less -# than this threshold, we assume that the files are the same. We need this -# because the zip file is served from a set of mirrors with slightly different -# Last-Modified times. -my $newnessThreshold = 30; -my $sourceDir = sourceDir(); my $file = "WebKitAuxiliaryLibrary"; my $zipFile = "$file.zip"; my $auxiliaryLibsURL = "http://developer.apple.com/opensource/internet/$zipFile"; -my $webkitLibrariesDir = toUnixPath($ENV{'WEBKITLIBRARIESDIR'}) || "$sourceDir/WebKitLibraries/win"; -my $tmpRelativeDir = File::Temp::tempdir("webkitlibsXXXXXXX", TMPDIR => 1, CLEANUP => 1); -my $tmpAbsDir = File::Spec->rel2abs($tmpRelativeDir); - -print "Checking Last-Modified date of $zipFile...\n"; - -my $result = system "curl -s -I $auxiliaryLibsURL | grep Last-Modified > \"$tmpAbsDir/$file.headers\""; - -if (WEXITSTATUS($result)) { - print STDERR "Couldn't check Last-Modified date of new $zipFile.\n"; - print STDERR "Please ensure that $auxiliaryLibsURL is reachable.\n"; - - if (! -f "$webkitLibrariesDir/$file.headers") { - print STDERR "Unable to check Last-Modified date and no version of $file to fall back to.\n"; - exit 1; - } - - print STDERR "Falling back to existing version of $file.\n"; - exit 0; -} - -if (open NEW, "$tmpAbsDir/$file.headers") { - my $new = lastModifiedToUnixTime(<NEW>); - close NEW; - - if (defined $new && open OLD, "$webkitLibrariesDir/$file.headers") { - my $old = lastModifiedToUnixTime(<OLD>); - close OLD; - if (defined $old && abs($new - $old) < $newnessThreshold) { - print "Current $file is up to date\n"; - exit 0; - } - } -} - -print "Downloading $zipFile...\n\n"; -$result = system "curl -o \"$tmpAbsDir/$zipFile\" $auxiliaryLibsURL"; -die "Couldn't download $zipFile!" if $result; - -$result = system "unzip", "-q", "-d", $tmpAbsDir, "$tmpAbsDir/$zipFile"; -die "Couldn't unzip $zipFile." if $result; - -print "\nInstalling $file...\n"; - -sub wanted -{ - my $relativeName = File::Spec->abs2rel($File::Find::name, "$tmpAbsDir/$file/win"); - my $destination = "$webkitLibrariesDir/$relativeName"; - - if (-d $_) { - mkdir $destination; - return; - } - - system "cp", $_, $destination; -} - -File::Find::find(\&wanted, "$tmpAbsDir/$file"); - -$result = system "mv", "$tmpAbsDir/$file.headers", $webkitLibrariesDir; -print STDERR "Couldn't move $file.headers to $webkitLibrariesDir" . ".\n" if $result; - -print "The $file has been sucessfully installed in\n $webkitLibrariesDir\n"; -exit; - -sub toUnixPath -{ - my $path = shift; - return unless $path; - chomp($path = `cygpath -u '$path'`); - return $path; -} - -sub lastModifiedToUnixTime($) -{ - my ($str) = @_; +my $command = "$FindBin::Bin/update-webkit-dependency"; - $str =~ /^Last-Modified: (.*)$/ or return; - return str2time($1); -} +system("perl", $command, $auxiliaryLibsURL, "win") == 0 or die; diff --git a/Tools/Scripts/update-webkit-dependency b/Tools/Scripts/update-webkit-dependency new file mode 100755 index 0000000..1ad4d6d --- /dev/null +++ b/Tools/Scripts/update-webkit-dependency @@ -0,0 +1,157 @@ +#!/usr/bin/perl -w + +# Copyright (C) 2005, 2006, 2007 Apple Computer, Inc. All rights reserved. +# Copyright (C) 2011 Carl Lobo. 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. + +# Updates a development environment to the new WebKitAuxiliaryLibrary + +use strict; +use warnings; + +use File::Find; +use File::Spec; +use File::Temp (); +use FindBin; +use HTTP::Date qw(str2time); +use POSIX; +use lib $FindBin::Bin; +use webkitdirs; + +if ($#ARGV != 1) { + die <<EOF; +Usage: + update-webkit-dependancy <URL with the dependancy zip file> <*prefix dir inside zip without filename> + + * If filename is requirements.zip and the contents of the zipfile are "requirements/x" then prefix = "." + * If filename is xyz.zip and the contents of the zipfile are xyz/abc/x" then prefix = "abc" + * x is lib or include or bin. +EOF +} + +sub lastModifiedToUnixTime($); +sub getLibraryName($); + +# Time in seconds that the new zip file must be newer than the old for us to +# consider them to be different. If the difference in modification time is less +# than this threshold, we assume that the files are the same. We need this +# because the zip file is served from a set of mirrors with slightly different +# Last-Modified times. +my $newnessThreshold = 30; + +my $libsURL = shift; +my $prefixInZip = shift; +my $sourceDir = sourceDir(); +my $file = getLibraryName($libsURL); +my $zipFile = "$file.zip"; +my $webkitLibrariesDir = toUnixPath($ENV{'WEBKITLIBRARIESDIR'}) || "$sourceDir/WebKitLibraries/win"; +my $tmpRelativeDir = File::Temp::tempdir("webkitlibsXXXXXXX", TMPDIR => 1, CLEANUP => 1); +my $tmpAbsDir = File::Spec->rel2abs($tmpRelativeDir); + +print "Checking Last-Modified date of $zipFile...\n"; + +my $result = system "curl -s -I $libsURL | grep Last-Modified > \"$tmpAbsDir/$file.headers\""; + +if (WEXITSTATUS($result)) { + print STDERR "Couldn't check Last-Modified date of new $zipFile.\n"; + print STDERR "Please ensure that $libsURL is reachable.\n"; + + if (! -f "$webkitLibrariesDir/$file.headers") { + print STDERR "Unable to check Last-Modified date and no version of $file to fall back to.\n"; + exit 1; + } + + print STDERR "Falling back to existing version of $file.\n"; + exit 0; +} + +if (open NEW, "$tmpAbsDir/$file.headers") { + my $new = lastModifiedToUnixTime(<NEW>); + close NEW; + + if (defined $new && open OLD, "$webkitLibrariesDir/$file.headers") { + my $old = lastModifiedToUnixTime(<OLD>); + close OLD; + if (defined $old && abs($new - $old) < $newnessThreshold) { + print "Current $file is up to date\n"; + exit 0; + } + } +} + +print "Downloading $zipFile...\n\n"; +$result = system "curl -o \"$tmpAbsDir/$zipFile\" $libsURL"; +die "Couldn't download $zipFile!" if $result; + +$result = system "unzip", "-q", "-d", $tmpAbsDir, "$tmpAbsDir/$zipFile"; +die "Couldn't unzip $zipFile." if $result; + +print "\nInstalling $file...\n"; + +sub wanted +{ + my $relativeName = File::Spec->abs2rel($File::Find::name, "$tmpAbsDir/$file/$prefixInZip"); + my $destination = "$webkitLibrariesDir/$relativeName"; + + if (-d $_) { + mkdir $destination; + return; + } + + system "cp", $_, $destination; +} + +File::Find::find(\&wanted, "$tmpAbsDir/$file"); + +$result = system "mv", "$tmpAbsDir/$file.headers", $webkitLibrariesDir; +print STDERR "Couldn't move $file.headers to $webkitLibrariesDir" . ".\n" if $result; + +print "The $file has been sucessfully installed in\n $webkitLibrariesDir\n"; +exit; + +sub toUnixPath +{ + my $path = shift; + return unless $path; + chomp($path = `cygpath -u '$path'`); + return $path; +} + +sub lastModifiedToUnixTime($) +{ + my ($str) = @_; + + $str =~ /^Last-Modified: (.*)$/ or return; + return str2time($1); +} + +sub getLibraryName($) +{ + my $url = shift; + $url =~ m#/([^/]+)\.zip$#; + return $1; +} + diff --git a/Tools/Scripts/update-webkit-localizable-strings b/Tools/Scripts/update-webkit-localizable-strings index 0a0ada9..ceb25a5 100755 --- a/Tools/Scripts/update-webkit-localizable-strings +++ b/Tools/Scripts/update-webkit-localizable-strings @@ -35,7 +35,7 @@ use lib $FindBin::Bin; use webkitdirs; # WebKit and WebKit2 strings go into WebCore's Localizable.strings. -my @directoriesToScan = ("Source/WebCore", "Source/WebKit/mac", "Source/WebKit2", "-Source/WebCore/icu", "-Source/WebKit/mac/icu"); +my @directoriesToScan = ("Source/WebCore", "Source/WebKit/mac", "Source/WebKit/win", "Source/WebKit2", "-Source/WebCore/icu", "-Source/WebKit/mac/icu"); my $fileToUpdate = "Source/WebCore/English.lproj/Localizable.strings"; @ARGV == 0 or die "Usage: " . basename($0) . "\n"; @@ -43,9 +43,3 @@ my $fileToUpdate = "Source/WebCore/English.lproj/Localizable.strings"; chdirWebKit(); system "Tools/Scripts/extract-localizable-strings", "-", $fileToUpdate, @directoriesToScan; - -# FIXME: the following can be removed and "Source/WebKit/win" added above once Windows uses WebCore's Localizable.strings. <rdar://problem/9119405> -my @webKitDirectoriesToScan = ("Source/WebKit/win"); -my $webKitFileToUpdate = "Source/WebKit/English.lproj/Localizable.strings"; - -system "Tools/Scripts/extract-localizable-strings", "-", $webKitFileToUpdate, @webKitDirectoriesToScan; diff --git a/Tools/Scripts/update-webkit-wincairo-libs b/Tools/Scripts/update-webkit-wincairo-libs new file mode 100755 index 0000000..15c7182 --- /dev/null +++ b/Tools/Scripts/update-webkit-wincairo-libs @@ -0,0 +1,40 @@ +#!/usr/bin/perl -w + +# Copyright (C) 2011 Carl Lobo. 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. + +# Updates a development environment to the new WebKitAuxiliaryLibrary + +use strict; +use warnings; +use FindBin; + +my $file = "WinCairoRequirements"; +my $zipFile = "$file.zip"; +my $winCairoLibsURL = "http://idisk.mac.com/bfulgham-Public/$zipFile"; +my $command = "$FindBin::Bin/update-webkit-dependency"; + +system("perl", $command, $winCairoLibsURL, ".") == 0 or die; diff --git a/Tools/Scripts/webkitdirs.pm b/Tools/Scripts/webkitdirs.pm index d27caba..e7afbea 100644 --- a/Tools/Scripts/webkitdirs.pm +++ b/Tools/Scripts/webkitdirs.pm @@ -67,6 +67,7 @@ my $isSymbian; my %qtFeatureDefaults; my $isGtk; my $isWinCE; +my $isWinCairo; my $isWx; my $isEfl; my @wxArgs; @@ -445,26 +446,24 @@ sub determinePassedConfiguration return if $searchedForPassedConfiguration; $searchedForPassedConfiguration = 1; - my $isWinCairo = checkForArgumentAndRemoveFromARGV("--wincairo"); - for my $i (0 .. $#ARGV) { my $opt = $ARGV[$i]; if ($opt =~ /^--debug$/i || $opt =~ /^--devel/i) { splice(@ARGV, $i, 1); $passedConfiguration = "Debug"; - $passedConfiguration .= "_Cairo_CFLite" if ($isWinCairo && isCygwin()); + $passedConfiguration .= "_Cairo_CFLite" if (isWinCairo() && isCygwin()); return; } if ($opt =~ /^--release$/i || $opt =~ /^--deploy/i) { splice(@ARGV, $i, 1); $passedConfiguration = "Release"; - $passedConfiguration .= "_Cairo_CFLite" if ($isWinCairo && isCygwin()); + $passedConfiguration .= "_Cairo_CFLite" if (isWinCairo() && isCygwin()); return; } if ($opt =~ /^--profil(e|ing)$/i) { splice(@ARGV, $i, 1); $passedConfiguration = "Profiling"; - $passedConfiguration .= "_Cairo_CFLite" if ($isWinCairo && isCygwin()); + $passedConfiguration .= "_Cairo_CFLite" if (isWinCairo() && isCygwin()); return; } } @@ -872,6 +871,18 @@ sub determineIsChromium() $isChromium = checkForArgumentAndRemoveFromARGV("--chromium"); } +sub isWinCairo() +{ + determineIsWinCairo(); + return $isWinCairo; +} + +sub determineIsWinCairo() +{ + return if defined($isWinCairo); + $isWinCairo = checkForArgumentAndRemoveFromARGV("--wincairo"); +} + sub isCygwin() { return ($^O eq "cygwin") || 0; @@ -1332,7 +1343,7 @@ sub buildWafProject chomp($wafCommand); } if ($shouldClean) { - return system $wafCommand, "clean", "distclean"; + return system $wafCommand, "uninstall", "clean", "distclean"; } return system $wafCommand, 'configure', 'build', 'install', @options; @@ -1645,7 +1656,6 @@ sub buildQMakeProject($@) if ($result ne 0) { die "Failed while running $qmakebin to generate derived sources for Tools!\n"; } - push @subdirs, "MiniBrowser"; push @subdirs, "WebKitTestRunner"; } } diff --git a/Tools/Scripts/webkitperl/VCSUtils_unittest/parseDiff.pl b/Tools/Scripts/webkitperl/VCSUtils_unittest/parseDiff.pl index 9fe077f..e195023 100644 --- a/Tools/Scripts/webkitperl/VCSUtils_unittest/parseDiff.pl +++ b/Tools/Scripts/webkitperl/VCSUtils_unittest/parseDiff.pl @@ -1198,7 +1198,7 @@ foreach my $testCase (@testCaseHashRefs) { open($fileHandle, "<", \$testCase->{inputText}); my $line = <$fileHandle>; - my @got = VCSUtils::parseDiff($fileHandle, $line); + my @got = VCSUtils::parseDiff($fileHandle, $line, {"shouldNotUseIndexPathEOL" => 1}); my $expectedReturn = $testCase->{expectedReturn}; is_deeply(\@got, $expectedReturn, "$testNameStart return value."); diff --git a/Tools/Scripts/webkitperl/VCSUtils_unittest/parseDiffWithMockFiles.pl b/Tools/Scripts/webkitperl/VCSUtils_unittest/parseDiffWithMockFiles.pl new file mode 100644 index 0000000..307f3a7 --- /dev/null +++ b/Tools/Scripts/webkitperl/VCSUtils_unittest/parseDiffWithMockFiles.pl @@ -0,0 +1,305 @@ +#!/usr/bin/perl -w +# +# Copyright (C) 2011 Research In Motion Limited. All rights reserved. +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +# Unit tests of parseDiff() with mock files; test override of patch EOL with EOL of target file. + +use strict; +use warnings; + +use File::Temp; +use POSIX qw/getcwd/; +use Test::More; +use VCSUtils; + +my $gitDiffHeaderForNewFile = <<EOF; +diff --git a/Makefile b/Makefile +new file mode 100644 +index 0000000..756e864 +--- /dev/null ++++ b/Makefile +@@ -0,0 +1,17 @@ +EOF + +my $gitDiffHeader = <<EOF; +diff --git a/Makefile b/Makefile +index 756e864..04d2ae1 100644 +--- a/Makefile ++++ b/Makefile +@@ -1,3 +1,4 @@ +EOF + +my $svnConvertedGitDiffHeader = <<EOF; +Index: Makefile +index 756e864..04d2ae1 100644 +--- Makefile ++++ Makefile +@@ -1,3 +1,4 @@ +EOF + +my $svnConvertedGitDiffHeaderForNewFile = <<EOF; +Index: Makefile +new file mode 100644 +index 0000000..756e864 +--- Makefile ++++ Makefile +@@ -0,0 +1,17 @@ +EOF + +my $svnDiffHeaderForNewFile = <<EOF; +Index: Makefile +=================================================================== +--- Makefile (revision 0) ++++ Makefile (revision 0) +@@ -0,0 +1,17 @@ +EOF + +my $svnDiffHeader = <<EOF; +Index: Makefile +=================================================================== +--- Makefile (revision 53052) ++++ Makefile (working copy) +@@ -1,3 +1,4 @@ +EOF + +my $diffBody = <<EOF; ++ + MODULES = JavaScriptCore JavaScriptGlue WebCore WebKit WebKitTools + + all: +EOF + +my $MakefileContents = <<EOF; +MODULES = JavaScriptCore JavaScriptGlue WebCore WebKit WebKitTools + +all: +EOF + +my $mockDir = File::Temp->tempdir("parseDiffXXXX", CLEANUP => 1); +writeToFile(File::Spec->catfile($mockDir, "MakefileWithUnixEOL"), $MakefileContents); +writeToFile(File::Spec->catfile($mockDir, "MakefileWithWindowsEOL"), toWindowsLineEndings($MakefileContents)); + +# The array of test cases. +my @testCaseHashRefs = ( +### +# SVN test cases +## +{ + # New test + diffName => "SVN: Patch with Unix line endings and IndexPath has Unix line endings", + inputText => substituteString($svnDiffHeader, "Makefile", "MakefileWithUnixEOL") . $diffBody, + expectedReturn => [ +[{ + svnConvertedText => substituteString($svnDiffHeader, "Makefile", "MakefileWithUnixEOL") . $diffBody, # Same as input text + indexPath => "MakefileWithUnixEOL", + isSvn => 1, + sourceRevision => "53052", +}], +undef], + expectedNextLine => undef, +}, +{ + # New test + diffName => "SVN: Patch with Windows line endings and IndexPath has Unix line endings", + inputText => substituteString($svnDiffHeader, "Makefile", "MakefileWithUnixEOL") . toWindowsLineEndings($diffBody), + expectedReturn => [ +[{ + svnConvertedText => substituteString($svnDiffHeader, "Makefile", "MakefileWithUnixEOL") . $diffBody, + indexPath => "MakefileWithUnixEOL", + isSvn => 1, + sourceRevision => "53052", +}], +undef], + expectedNextLine => undef, +}, +{ + # New test + diffName => "SVN: Patch with Windows line endings and IndexPath has Windows line endings", + inputText => substituteString($svnDiffHeader, "Makefile", "MakefileWithWindowsEOL") . toWindowsLineEndings($diffBody), + expectedReturn => [ +[{ + svnConvertedText => substituteString($svnDiffHeader, "Makefile", "MakefileWithWindowsEOL") . toWindowsLineEndings($diffBody), # Same as input text + indexPath => "MakefileWithWindowsEOL", + isSvn => 1, + sourceRevision => "53052", +}], +undef], + expectedNextLine => undef, +}, +{ + # New test + diffName => "SVN: Patch with Unix line endings and IndexPath has Windows line endings", + inputText => substituteString($svnDiffHeader, "Makefile", "MakefileWithWindowsEOL") . $diffBody, + expectedReturn => [ +[{ + svnConvertedText => substituteString($svnDiffHeader, "Makefile", "MakefileWithWindowsEOL") . toWindowsLineEndings($diffBody), + indexPath => "MakefileWithWindowsEOL", + isSvn => 1, + sourceRevision => "53052", +}], +undef], + expectedNextLine => undef, +}, +{ + # New test + diffName => "SVN: Patch with Unix line endings and nonexistent IndexPath", + inputText => substituteString($svnDiffHeaderForNewFile, "Makefile", "NonexistentFile") . $diffBody, + expectedReturn => [ +[{ + svnConvertedText => substituteString($svnDiffHeaderForNewFile, "Makefile", "NonexistentFile") . $diffBody, # Same as input text + indexPath => "NonexistentFile", + isSvn => 1, + isNew => 1, +}], +undef], + expectedNextLine => undef, +}, +{ + # New test + diffName => "SVN: Patch with Windows line endings and nonexistent IndexPath", + inputText => substituteString($svnDiffHeaderForNewFile, "Makefile", "NonexistentFile") . toWindowsLineEndings($diffBody), + expectedReturn => [ +[{ + svnConvertedText => substituteString($svnDiffHeaderForNewFile, "Makefile", "NonexistentFile") . toWindowsLineEndings($diffBody), # Same as input text + indexPath => "NonexistentFile", + isSvn => 1, + isNew => 1, +}], +undef], + expectedNextLine => undef, +}, +### +# Git test cases +## +{ + # New test + diffName => "Git: Patch with Unix line endings and IndexPath has Unix line endings", + inputText => substituteString($gitDiffHeader, "Makefile", "MakefileWithUnixEOL") . $diffBody, + expectedReturn => [ +[{ + svnConvertedText => substituteString($svnConvertedGitDiffHeader, "Makefile", "MakefileWithUnixEOL") . $diffBody, # Same as input text + indexPath => "MakefileWithUnixEOL", + isGit => 1, +}], +undef], + expectedNextLine => undef, +}, +{ + # New test + diffName => "Git: Patch with Windows line endings and IndexPath has Unix line endings", + inputText => substituteString($gitDiffHeader, "Makefile", "MakefileWithUnixEOL") . toWindowsLineEndings($diffBody), + expectedReturn => [ +[{ + svnConvertedText => substituteString($svnConvertedGitDiffHeader, "Makefile", "MakefileWithUnixEOL") . $diffBody, + indexPath => "MakefileWithUnixEOL", + isGit => 1, +}], +undef], + expectedNextLine => undef, +}, +{ + # New test + diffName => "Git: Patch with Windows line endings and IndexPath has Windows line endings", + inputText => substituteString($gitDiffHeader, "Makefile", "MakefileWithWindowsEOL") . toWindowsLineEndings($diffBody), + expectedReturn => [ +[{ + svnConvertedText => substituteString($svnConvertedGitDiffHeader, "Makefile", "MakefileWithWindowsEOL") . toWindowsLineEndings($diffBody), # Same as input text + indexPath => "MakefileWithWindowsEOL", + isGit => 1, +}], +undef], + expectedNextLine => undef, +}, +{ + # New test + diffName => "Git: Patch with Unix line endings and IndexPath has Windows line endings", + inputText => substituteString($gitDiffHeader, "Makefile", "MakefileWithWindowsEOL") . $diffBody, + expectedReturn => [ +[{ + svnConvertedText => substituteString($svnConvertedGitDiffHeader, "Makefile", "MakefileWithWindowsEOL") . toWindowsLineEndings($diffBody), + indexPath => "MakefileWithWindowsEOL", + isGit => 1, +}], +undef], + expectedNextLine => undef, +}, +{ + # New test + diffName => "Git: Patch with Unix line endings and nonexistent IndexPath", + inputText => substituteString($gitDiffHeaderForNewFile, "Makefile", "NonexistentFile") . $diffBody, + expectedReturn => [ +[{ + svnConvertedText => substituteString($svnConvertedGitDiffHeaderForNewFile, "Makefile", "NonexistentFile") . $diffBody, # Same as input text + indexPath => "NonexistentFile", + isGit => 1, + isNew => 1, +}], +undef], + expectedNextLine => undef, +}, +{ + # New test + diffName => "Git: Patch with Windows line endings and nonexistent IndexPath", + inputText => substituteString($gitDiffHeaderForNewFile, "Makefile", "NonexistentFile") . toWindowsLineEndings($diffBody), + expectedReturn => [ +[{ + svnConvertedText => substituteString($svnConvertedGitDiffHeaderForNewFile, "Makefile", "NonexistentFile") . toWindowsLineEndings($diffBody), # Same as input text + indexPath => "NonexistentFile", + isGit => 1, + isNew => 1, +}], +undef], + expectedNextLine => undef, +}, +); + +my $testCasesCount = @testCaseHashRefs; +plan(tests => 2 * $testCasesCount); # Total number of assertions. + +my $savedCWD = getcwd(); +chdir($mockDir) or die; +foreach my $testCase (@testCaseHashRefs) { + my $testNameStart = "parseDiff(): $testCase->{diffName}: comparing"; + + my $fileHandle; + open($fileHandle, "<", \$testCase->{inputText}); + my $line = <$fileHandle>; + + my @got = VCSUtils::parseDiff($fileHandle, $line); + my $expectedReturn = $testCase->{expectedReturn}; + + is_deeply(\@got, $expectedReturn, "$testNameStart return value."); + + my $gotNextLine = <$fileHandle>; + is($gotNextLine, $testCase->{expectedNextLine}, "$testNameStart next read line."); +} +chdir($savedCWD); + +sub substituteString +{ + my ($string, $searchString, $replacementString) = @_; + $string =~ s/$searchString/$replacementString/g; + return $string; +} + +sub writeToFile +{ + my ($file, $text) = @_; + open(FILE, ">$file") or die; + print FILE $text; + close(FILE); +} diff --git a/Tools/Scripts/webkitperl/VCSUtils_unittest/parseFirstEOL.pl b/Tools/Scripts/webkitperl/VCSUtils_unittest/parseFirstEOL.pl new file mode 100644 index 0000000..367ad1d --- /dev/null +++ b/Tools/Scripts/webkitperl/VCSUtils_unittest/parseFirstEOL.pl @@ -0,0 +1,63 @@ +#!/usr/bin/perl -w +# +# Copyright (C) 2011 Research In Motion Limited. All rights reserved. +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +# Unit tests of VCSUtils::parseFirstEOL(). + +use strict; +use warnings; + +use Test::Simple tests => 7; +use VCSUtils; + +my $title; + +# New test +$title = "parseFirstEOL: Empty string."; +ok(!defined(firstEOLInString("")), $title); + +# New test +$title = "parseFirstEOL: Line without a line ending character"; +ok(!defined(firstEOLInString("This line doesn't have a line ending character.")), $title); + +# New test +$title = "parseFirstEOL: Line with Windows line ending."; +ok(firstEOLInString("This line ends with a Windows line ending.\r\n") eq "\r\n", $title); + +# New test +$title = "parseFirstEOL: Line with Unix line ending."; +ok(firstEOLInString("This line ends with a Unix line ending.\n") eq "\n", $title); + +# New test +$title = "parseFirstEOL: Line with Mac line ending."; +ok(firstEOLInString("This line ends with a Mac line ending.\r") eq "\r", $title); + +# New test +$title = "parseFirstEOL: Line with Mac line ending followed by line without a line ending."; +ok(firstEOLInString("This line ends with a Mac line ending.\rThis line doesn't have a line ending.") eq "\r", $title); + +# New test +$title = "parseFirstEOL: Line with a mix of line endings."; +ok(firstEOLInString("This line contains a mix of line endings.\r\n\r\n\r\r\n\n\n\n") eq "\r\n", $title); + +sub firstEOLInString +{ + my ($string) = @_; + my $fileHandle; + open($fileHandle, "<", \$string); + return parseFirstEOL($fileHandle); +} diff --git a/Tools/Scripts/webkitperl/VCSUtils_unittest/removeEOL.pl b/Tools/Scripts/webkitperl/VCSUtils_unittest/removeEOL.pl index 8bd8e90..6880214 100644 --- a/Tools/Scripts/webkitperl/VCSUtils_unittest/removeEOL.pl +++ b/Tools/Scripts/webkitperl/VCSUtils_unittest/removeEOL.pl @@ -37,20 +37,20 @@ my $title; # New test $title = "removeEOL: Undefined argument."; -ok(removeEOL(undef) eq ""); +ok(removeEOL(undef) eq "", $title); # New test $title = "removeEOL: Line with Windows line ending."; -ok(removeEOL("This line ends with a Windows line ending.\r\n") eq "This line ends with a Windows line ending."); +ok(removeEOL("This line ends with a Windows line ending.\r\n") eq "This line ends with a Windows line ending.", $title); # New test $title = "removeEOL: Line with Unix line ending."; -ok(removeEOL("This line ends with a Unix line ending.\n") eq "This line ends with a Unix line ending."); +ok(removeEOL("This line ends with a Unix line ending.\n") eq "This line ends with a Unix line ending.", $title); # New test $title = "removeEOL: Line with Mac line ending."; -ok(removeEOL("This line ends with a Mac line ending.\r") eq "This line ends with a Mac line ending."); +ok(removeEOL("This line ends with a Mac line ending.\r") eq "This line ends with a Mac line ending.", $title); # New test $title = "removeEOL: Line with a mix of line endings."; -ok(removeEOL("This line contains a mix of line endings.\r\n\r\n\r\r\n\n\n\n") eq "This line contains a mix of line endings."); +ok(removeEOL("This line contains a mix of line endings.\r\n\r\n\r\r\n\n\n\n") eq "This line contains a mix of line endings.", $title); diff --git a/Tools/Scripts/webkitperl/httpd.pm b/Tools/Scripts/webkitperl/httpd.pm index 5795340..3a40b4e 100644 --- a/Tools/Scripts/webkitperl/httpd.pm +++ b/Tools/Scripts/webkitperl/httpd.pm @@ -63,7 +63,6 @@ $tmpDir = convertMsysPath($tmpDir) if isMsys(); my $httpdLockPrefix = "WebKitHttpd.lock."; my $myLockFile; my $exclusiveLockFile = File::Spec->catfile($tmpDir, "WebKit.lock"); -my $httpdPath; my $httpdPidDir = File::Spec->catfile($tmpDir, "WebKit"); my $httpdPidFile = File::Spec->catfile($httpdPidDir, "httpd.pid"); my $httpdPid; @@ -76,6 +75,7 @@ $SIG{'TERM'} = 'handleInterrupt'; sub getHTTPDPath { + my $httpdPath; if (isDebianBased()) { $httpdPath = "/usr/sbin/apache2"; } elsif (isMsys()) { @@ -130,7 +130,7 @@ sub getHTTPDConfigPathForTestDirectory my ($testDirectory) = @_; die "No test directory has been specified." unless ($testDirectory); my $httpdConfig; - getHTTPDPath(); + my $httpdPath = getHTTPDPath(); if (isCygwin()) { my $windowsConfDirectory = "$testDirectory/http/conf/"; unless (-x "/usr/lib/apache/libphp4.dll") { @@ -173,7 +173,7 @@ sub openHTTPD(@) unlink $httpdPidFile; } - $httpdPath = "/usr/sbin/httpd" unless ($httpdPath); + my $httpdPath = getHTTPDPath(); open2(">&1", \*HTTPDIN, $httpdPath, @args); diff --git a/Tools/Scripts/webkitpy/common/checkout/scm.py b/Tools/Scripts/webkitpy/common/checkout/scm.py index e436402..3e8d5e5 100644 --- a/Tools/Scripts/webkitpy/common/checkout/scm.py +++ b/Tools/Scripts/webkitpy/common/checkout/scm.py @@ -134,8 +134,9 @@ def commit_error_handler(error): class AuthenticationError(Exception): - def __init__(self, server_host): + def __init__(self, server_host, prompt_for_password=False): self.server_host = server_host + self.prompt_for_password = prompt_for_password class AmbiguousCommitError(Exception): @@ -291,7 +292,7 @@ class SCM: def revert_files(self, file_paths): self._subclass_must_implement() - def commit_with_message(self, message, username=None, git_commit=None, force_squash=False, changed_files=None): + def commit_with_message(self, message, username=None, password=None, git_commit=None, force_squash=False, changed_files=None): self._subclass_must_implement() def svn_commit_log(self, svn_revision): @@ -319,8 +320,19 @@ class SCM: return [] -class SVN(SCM): - # FIXME: We should move these values to a WebKit-specific config file. +# A mixin class that represents common functionality for SVN and Git-SVN. +class SVNRepository: + def has_authorization_for_realm(self, realm, home_directory=os.getenv("HOME")): + # Assumes find and grep are installed. + if not os.path.isdir(os.path.join(home_directory, ".subversion")): + return False + find_args = ["find", ".subversion", "-type", "f", "-exec", "grep", "-q", realm, "{}", ";", "-print"] + find_output = self.run(find_args, cwd=home_directory, error_handler=Executive.ignore_error).rstrip() + return find_output and os.path.isfile(os.path.join(home_directory, find_output)) + + +class SVN(SCM, SVNRepository): + # FIXME: These belong in common.config.urls svn_server_host = "svn.webkit.org" svn_server_realm = "<http://svn.webkit.org:80> Mac OS Forge" @@ -374,14 +386,6 @@ class SVN(SCM): def commit_success_regexp(): return "^Committed revision (?P<svn_revision>\d+)\.$" - def has_authorization_for_realm(self, realm=svn_server_realm, home_directory=os.getenv("HOME")): - # Assumes find and grep are installed. - if not os.path.isdir(os.path.join(home_directory, ".subversion")): - return False - find_args = ["find", ".subversion", "-type", "f", "-exec", "grep", "-q", realm, "{}", ";", "-print"]; - find_output = self.run(find_args, cwd=home_directory, error_handler=Executive.ignore_error).rstrip() - return find_output and os.path.isfile(os.path.join(home_directory, find_output)) - @memoized def svn_version(self): return self.run(['svn', '--version', '--quiet']) @@ -556,11 +560,11 @@ class SVN(SCM): # FIXME: This should probably use cwd=self.checkout_root. self.run(['svn', 'revert'] + file_paths) - def commit_with_message(self, message, username=None, git_commit=None, force_squash=False, changed_files=None): + def commit_with_message(self, message, username=None, password=None, git_commit=None, force_squash=False, changed_files=None): # git-commit and force are not used by SVN. svn_commit_args = ["svn", "commit"] - if not username and not self.has_authorization_for_realm(): + if not username and not self.has_authorization_for_realm(self.svn_server_realm): raise AuthenticationError(self.svn_server_host) if username: svn_commit_args.extend(["--username", username]) @@ -577,8 +581,7 @@ class SVN(SCM): # Return a string which looks like a commit so that things which parse this output will succeed. return "Dry run, no commit.\nCommitted revision 0." - # FIXME: Should this use cwd=self.checkout_root? - return self.run(svn_commit_args, error_handler=commit_error_handler) + return self.run(svn_commit_args, cwd=self.checkout_root, error_handler=commit_error_handler) def svn_commit_log(self, svn_revision): svn_revision = self.strip_r_from_svn_revision(svn_revision) @@ -599,7 +602,7 @@ class SVN(SCM): # All git-specific logic should go here. -class Git(SCM): +class Git(SCM, SVNRepository): def __init__(self, cwd, executive=None): SCM.__init__(self, cwd, executive) self._check_git_architecture() @@ -834,7 +837,7 @@ class Git(SCM): if num_local_commits > 1 or (num_local_commits > 0 and not working_directory_is_clean): raise AmbiguousCommitError(num_local_commits, working_directory_is_clean) - def commit_with_message(self, message, username=None, git_commit=None, force_squash=False, changed_files=None): + def commit_with_message(self, message, username=None, password=None, git_commit=None, force_squash=False, changed_files=None): # Username is ignored during Git commits. working_directory_is_clean = self.working_directory_is_clean() @@ -844,7 +847,7 @@ class Git(SCM): if working_directory_is_clean: raise ScriptError(message="The working copy is not modified. --git-commit=HEAD.. only commits working copy changes.") self.commit_locally_with_message(message) - return self._commit_on_branch(message, 'HEAD') + return self._commit_on_branch(message, 'HEAD', username=username, password=password) # Need working directory changes to be committed so we can checkout the merge branch. if not working_directory_is_clean: @@ -852,15 +855,15 @@ class Git(SCM): # That will modify the working-copy and cause us to hit this error. # The ChangeLog modification could be made to modify the existing local commit. raise ScriptError(message="Working copy is modified. Cannot commit individual git_commits.") - return self._commit_on_branch(message, git_commit) + return self._commit_on_branch(message, git_commit, username=username, password=password) if not force_squash: self._assert_can_squash(working_directory_is_clean) self.run(['git', 'reset', '--soft', self.remote_merge_base()]) self.commit_locally_with_message(message) - return self.push_local_commits_to_server() + return self.push_local_commits_to_server(username=username, password=password) - def _commit_on_branch(self, message, git_commit): + def _commit_on_branch(self, message, git_commit, username=None, password=None): branch_ref = self.run(['git', 'symbolic-ref', 'HEAD']).strip() branch_name = branch_ref.replace('refs/heads/', '') commit_ids = self.commit_ids_from_commitish_arguments([git_commit]) @@ -889,7 +892,7 @@ class Git(SCM): self.run(['git', 'cherry-pick', '--no-commit', commit]) self.run(['git', 'commit', '-m', message]) - output = self.push_local_commits_to_server() + output = self.push_local_commits_to_server(username=username, password=password) except Exception, e: log("COMMIT FAILED: " + str(e)) output = "Commit failed." @@ -937,11 +940,15 @@ class Git(SCM): def commit_locally_with_message(self, message): self.run(['git', 'commit', '--all', '-F', '-'], input=message) - def push_local_commits_to_server(self): + def push_local_commits_to_server(self, username=None, password=None): dcommit_command = ['git', 'svn', 'dcommit'] if self.dryrun: dcommit_command.append('--dry-run') - output = self.run(dcommit_command, error_handler=commit_error_handler) + if not self.has_authorization_for_realm(SVN.svn_server_realm): + raise AuthenticationError(SVN.svn_server_host, prompt_for_password=True) + if username: + dcommit_command.extend(["--username", username]) + output = self.run(dcommit_command, error_handler=commit_error_handler, input=password) # Return a string which looks like a commit so that things which parse this output will succeed. if self.dryrun: output += "\nCommitted r0" diff --git a/Tools/Scripts/webkitpy/common/checkout/scm_unittest.py b/Tools/Scripts/webkitpy/common/checkout/scm_unittest.py index 79b354d..ab3f45a 100644 --- a/Tools/Scripts/webkitpy/common/checkout/scm_unittest.py +++ b/Tools/Scripts/webkitpy/common/checkout/scm_unittest.py @@ -650,6 +650,13 @@ Q1dTBx0AAAB42itg4GlgYJjGwMDDyODMxMDw34GBgQEAJPQDJA== commit_text = self.scm.commit_with_message("yet another test commit", username) self.assertEqual(self.scm.svn_revision_from_commit_text(commit_text), '0') + def test_commit_in_subdir(self, username=None): + write_into_file_at_path('test_dir/test_file3', 'more test content') + os.chdir("test_dir") + commit_text = self.scm.commit_with_message("another test commit", username) + os.chdir("..") + self.assertEqual(self.scm.svn_revision_from_commit_text(commit_text), '6') + def test_commit_text_parsing(self): self._shared_test_commit_with_message() @@ -657,7 +664,7 @@ Q1dTBx0AAAB42itg4GlgYJjGwMDDyODMxMDw34GBgQEAJPQDJA== self._shared_test_commit_with_message("dbates@webkit.org") def test_commit_without_authorization(self): - self.scm.has_authorization_for_realm = lambda: False + self.scm.has_authorization_for_realm = lambda realm: False self.assertRaises(AuthenticationError, self._shared_test_commit_with_message) def test_has_authorization_for_realm(self): @@ -667,7 +674,7 @@ Q1dTBx0AAAB42itg4GlgYJjGwMDDyODMxMDw34GBgQEAJPQDJA== os.mkdir(svn_config_dir_path) fake_webkit_auth_file = os.path.join(svn_config_dir_path, "fake_webkit_auth_file") write_into_file_at_path(fake_webkit_auth_file, SVN.svn_server_realm) - self.assertTrue(scm.has_authorization_for_realm(home_directory=fake_home_dir)) + self.assertTrue(scm.has_authorization_for_realm(SVN.svn_server_realm, home_directory=fake_home_dir)) os.remove(fake_webkit_auth_file) os.rmdir(svn_config_dir_path) os.rmdir(fake_home_dir) @@ -677,7 +684,7 @@ Q1dTBx0AAAB42itg4GlgYJjGwMDDyODMxMDw34GBgQEAJPQDJA== fake_home_dir = tempfile.mkdtemp(suffix="fake_home_dir") svn_config_dir_path = os.path.join(fake_home_dir, ".subversion") os.mkdir(svn_config_dir_path) - self.assertFalse(scm.has_authorization_for_realm(home_directory=fake_home_dir)) + self.assertFalse(scm.has_authorization_for_realm(SVN.svn_server_realm, home_directory=fake_home_dir)) os.rmdir(svn_config_dir_path) os.rmdir(fake_home_dir) diff --git a/Tools/Scripts/webkitpy/common/config/build.py b/Tools/Scripts/webkitpy/common/config/build.py index 42d0721..d25d606 100644 --- a/Tools/Scripts/webkitpy/common/config/build.py +++ b/Tools/Scripts/webkitpy/common/config/build.py @@ -97,10 +97,12 @@ def _should_file_trigger_build(target_platform, file): (r"(?:^|/)GNUmakefile\.am$", ["gtk"]), (r"/\w+Chromium\w*\.(?:cpp|h|mm)$", ["chromium"]), (r"Mac\.(?:cpp|h|mm)$", ["mac"]), + (r"\.(?:vcproj|vsprops|sln)$", ["win"]), (r"\.exp(?:\.in)?$", ["mac"]), (r"\.gypi?", ["chromium"]), (r"\.order$", ["mac"]), (r"\.pr[io]$", ["qt"]), + (r"\.vcproj/", ["win"]), (r"\.xcconfig$", ["mac"]), (r"\.xcodeproj/", ["mac"]), ] diff --git a/Tools/Scripts/webkitpy/common/config/build_unittest.py b/Tools/Scripts/webkitpy/common/config/build_unittest.py index 9144874..6bd71e8 100644 --- a/Tools/Scripts/webkitpy/common/config/build_unittest.py +++ b/Tools/Scripts/webkitpy/common/config/build_unittest.py @@ -32,6 +32,7 @@ class ShouldBuildTest(unittest.TestCase): (["Websites/bugs.webkit.org/foo", "Source/WebCore/bar"], ["*"]), (["Websites/bugs.webkit.org/foo"], []), (["Source/JavaScriptCore/JavaScriptCore.xcodeproj/foo"], ["mac-leopard", "mac-snowleopard"]), + (["Source/JavaScriptCore/JavaScriptCore.vcproj/foo", "Source/WebKit2/win/WebKit2.vcproj", "Source/WebKit/win/WebKit.sln", "Tools/WebKitTestRunner/Configurations/WebKitTestRunnerCommon.vsprops"], ["win"]), (["Source/JavaScriptGlue/foo", "Source/WebCore/bar"], ["*"]), (["Source/JavaScriptGlue/foo"], ["mac-leopard", "mac-snowleopard"]), (["LayoutTests/foo"], ["*"]), diff --git a/Tools/Scripts/webkitpy/common/config/committers.py b/Tools/Scripts/webkitpy/common/config/committers.py index fd9bdbb..50506c8 100644 --- a/Tools/Scripts/webkitpy/common/config/committers.py +++ b/Tools/Scripts/webkitpy/common/config/committers.py @@ -90,7 +90,7 @@ committers_unable_to_review = [ Committer("Brett Wilson", "brettw@chromium.org", "brettx"), Committer("Cameron McCormack", "cam@webkit.org", "heycam"), Committer("Carlos Garcia Campos", ["cgarcia@igalia.com", "carlosgc@gnome.org", "carlosgc@webkit.org"], "KaL"), - Committer("Carol Szabo", "carol.szabo@nokia.com"), + Committer("Carol Szabo", "carol@webkit.org", "cszabo1"), Committer("Chang Shu", ["cshu@webkit.org", "Chang.Shu@nokia.com"], "cshu"), Committer("Chris Evans", "cevans@google.com"), Committer("Chris Petersen", "cpetersen@apple.com", "cpetersen"), @@ -129,6 +129,7 @@ committers_unable_to_review = [ Committer("Jakob Petsovits", ["jpetsovits@rim.com", "jpetso@gmx.at"], "jpetso"), Committer("Jakub Wieczorek", "jwieczorek@webkit.org", "fawek"), Committer("James Hawkins", ["jhawkins@chromium.org", "jhawkins@google.com"], "jhawkins"), + Committer("James Kozianski", ["koz@chromium.org", "koz@google.com"], "koz"), Committer("James Simonsen", "simonjam@chromium.org", "simonjam"), Committer("Jay Civelli", "jcivelli@chromium.org", "jcivelli"), Committer("Jeff Miller", "jeffm@apple.com", "jeffm"), @@ -204,8 +205,9 @@ committers_unable_to_review = [ Committer("Victor Wang", "victorw@chromium.org", "victorw"), Committer("Vitaly Repeshko", "vitalyr@chromium.org"), Committer("William Siegrist", "wsiegrist@apple.com", "wms"), + Committer("W. James MacLean", "wjmaclean@chromium.org", "wjmaclean"), Committer("Xiaomei Ji", "xji@chromium.org", "xji"), - Committer("Yael Aharon", "yael.aharon@nokia.com"), + Committer("Yael Aharon", "yael.aharon@nokia.com", "yael"), Committer("Yaar Schnitman", ["yaar@chromium.org", "yaar@google.com"]), Committer("Yong Li", ["yong.li.webkit@gmail.com", "yong.li@torchmobile.com"], "yong"), Committer("Yongjun Zhang", "yongjun.zhang@nokia.com"), diff --git a/Tools/Scripts/webkitpy/common/config/ports.py b/Tools/Scripts/webkitpy/common/config/ports.py index 9a5a269..444a4ac 100644 --- a/Tools/Scripts/webkitpy/common/config/ports.py +++ b/Tools/Scripts/webkitpy/common/config/ports.py @@ -30,6 +30,7 @@ import os import platform +import sys from webkitpy.common.system.executive import Executive @@ -43,7 +44,13 @@ class WebKitPort(object): @classmethod def script_shell_command(cls, script_name): - return [cls.script_path(script_name)] + script_path = cls.script_path(script_name) + # Win32 does not support shebang. We need to detect the interpreter ourself. + if sys.platform == 'win32': + interpreter = Executive.interpreter_for_script(script_path) + if interpreter: + return [interpreter, script_path] + return [script_path] @staticmethod def port(port_name): @@ -83,6 +90,14 @@ class WebKitPort(object): return cls.script_shell_command("update-webkit") @classmethod + def check_webkit_style_command(cls): + return cls.script_shell_command("check-webkit-style") + + @classmethod + def prepare_changelog_command(cls): + return cls.script_shell_command("prepare-ChangeLog") + + @classmethod def build_webkit_command(cls, build_style=None): command = cls.script_shell_command("build-webkit") if build_style == "debug": diff --git a/Tools/Scripts/webkitpy/common/net/bugzilla/bugzilla.py b/Tools/Scripts/webkitpy/common/net/bugzilla/bugzilla.py index 8daf92e..c781dfb 100644 --- a/Tools/Scripts/webkitpy/common/net/bugzilla/bugzilla.py +++ b/Tools/Scripts/webkitpy/common/net/bugzilla/bugzilla.py @@ -46,7 +46,7 @@ from webkitpy.common.config import committers from webkitpy.common.net.credentials import Credentials from webkitpy.common.system.user import User from webkitpy.thirdparty.autoinstalled.mechanize import Browser -from webkitpy.thirdparty.BeautifulSoup import BeautifulSoup, SoupStrainer +from webkitpy.thirdparty.BeautifulSoup import BeautifulSoup, BeautifulStoneSoup, SoupStrainer # FIXME: parse_bug_id should not be a free function. @@ -74,7 +74,9 @@ def parse_bug_id_from_changelog(message): match = re.search("^\s*" + Bugzilla.bug_url_long + "$", message, re.MULTILINE) if match: return int(match.group('bug_id')) - return None + # We weren't able to find a bug URL in the format used by prepare-ChangeLog. Fall back to the + # first bug URL found anywhere in the message. + return parse_bug_id(message) def timestamp(): return datetime.now().strftime("%Y%m%d%H%M%S") @@ -218,7 +220,8 @@ class Bugzilla(object): # script. self.browser.set_handle_robots(False) - # FIXME: Much of this should go into some sort of config module: + # FIXME: Much of this should go into some sort of config module, + # such as common.config.urls. bug_server_host = "bugs.webkit.org" bug_server_regex = "https?://%s/" % re.sub('\.', '\\.', bug_server_host) bug_server_url = "https://%s/" % bug_server_host @@ -270,7 +273,7 @@ class Bugzilla(object): def _string_contents(self, soup): # WebKit's bugzilla instance uses UTF-8. - # BeautifulSoup always returns Unicode strings, however + # BeautifulStoneSoup always returns Unicode strings, however # the .string method returns a (unicode) NavigableString. # NavigableString can confuse other parts of the code, so we # convert from NavigableString to a real unicode() object using unicode(). @@ -317,7 +320,7 @@ class Bugzilla(object): return [Bug(self._parse_bug_dictionary_from_xml(unicode(bug_xml)), self) for bug_xml in soup('bug')] def _parse_bug_dictionary_from_xml(self, page): - soup = BeautifulSoup(page) + soup = BeautifulStoneSoup(page, convertEntities=BeautifulStoneSoup.XML_ENTITIES) bug = {} bug["id"] = int(soup.find("bug_id").string) bug["title"] = self._string_contents(soup.find("short_desc")) diff --git a/Tools/Scripts/webkitpy/common/net/bugzilla/bugzilla_unittest.py b/Tools/Scripts/webkitpy/common/net/bugzilla/bugzilla_unittest.py index 2e75ca9..b996b7c 100644 --- a/Tools/Scripts/webkitpy/common/net/bugzilla/bugzilla_unittest.py +++ b/Tools/Scripts/webkitpy/common/net/bugzilla/bugzilla_unittest.py @@ -104,7 +104,7 @@ class BugzillaTest(unittest.TestCase): <bug> <bug_id>32585</bug_id> <creation_ts>2009-12-15 15:17 PST</creation_ts> - <short_desc>bug to test webkit-patch and commit-queue failures</short_desc> + <short_desc>bug to test webkit-patch's and commit-queue's failures</short_desc> <delta_ts>2009-12-27 21:04:50 PST</delta_ts> <reporter_accessible>1</reporter_accessible> <cclist_accessible>1</cclist_accessible> @@ -173,7 +173,7 @@ ZEZpbmlzaExvYWRXaXRoUmVhc29uOnJlYXNvbl07Cit9CisKIEBlbmQKIAogI2VuZGlmCg== _expected_example_bug_parsing = { "id" : 32585, - "title" : u"bug to test webkit-patch and commit-queue failures", + "title" : u"bug to test webkit-patch's and commit-queue's failures", "cc_emails" : ["foo@bar.com", "example@example.com"], "reporter_email" : "eric@webkit.org", "assigned_to_email" : "webkit-unassigned@lists.webkit.org", @@ -203,7 +203,7 @@ ZEZpbmlzaExvYWRXaXRoUmVhc29uOnJlYXNvbl07Cit9CisKIEBlbmQKIAogI2VuZGlmCg== ''' - self.assertEquals(None, parse_bug_id_from_changelog(commit_text)) + self.assertEquals(56988, parse_bug_id_from_changelog(commit_text)) commit_text = ''' 2011-03-23 Ojan Vafai <ojan@chromium.org> @@ -218,6 +218,25 @@ ZEZpbmlzaExvYWRXaXRoUmVhc29uOnJlYXNvbl07Cit9CisKIEBlbmQKIAogI2VuZGlmCg== self.assertEquals(12345, parse_bug_id_from_changelog(commit_text)) + commit_text = ''' +2011-03-31 Adam Roben <aroben@apple.com> + + Quote the executable path we pass to ::CreateProcessW + + This will ensure that spaces in the path will be interpreted correctly. + + Fixes <http://webkit.org/b/57569> Web process sometimes fails to launch when there are + spaces in its path + + Reviewed by Steve Falkenburg. + + * UIProcess/Launcher/win/ProcessLauncherWin.cpp: + (WebKit::ProcessLauncher::launchProcess): Surround the executable path in quotes. + + ''' + + self.assertEquals(57569, parse_bug_id_from_changelog(commit_text)) + # FIXME: This should move to a central location and be shared by more unit tests. def _assert_dictionaries_equal(self, actual, expected): diff --git a/Tools/Scripts/webkitpy/common/net/buildbot/buildbot.py b/Tools/Scripts/webkitpy/common/net/buildbot/buildbot.py index d23a6cc..5fdf184 100644 --- a/Tools/Scripts/webkitpy/common/net/buildbot/buildbot.py +++ b/Tools/Scripts/webkitpy/common/net/buildbot/buildbot.py @@ -267,7 +267,7 @@ class Build(object): class BuildBot(object): - # FIXME: This should move into some sort of webkit_config.py + # FIXME: This should move into common.config.urls. default_host = "build.webkit.org" def __init__(self, host=default_host): diff --git a/Tools/Scripts/webkitpy/common/net/credentials.py b/Tools/Scripts/webkitpy/common/net/credentials.py index 30480b3..d76405b 100644 --- a/Tools/Scripts/webkitpy/common/net/credentials.py +++ b/Tools/Scripts/webkitpy/common/net/credentials.py @@ -29,7 +29,6 @@ # # Python module for reading stored web credentials from the OS. -import getpass import os import platform import re @@ -149,7 +148,7 @@ class Credentials(object): if not username: username = User.prompt("%s login: " % self.host) if not password: - password = getpass.getpass("%s password for %s: " % (self.host, username)) + password = User.prompt_password("%s password for %s: " % (self.host, username)) self._offer_to_store_credentials_in_keyring(username, password) return (username, password) diff --git a/Tools/Scripts/webkitpy/common/net/layouttestresults.py b/Tools/Scripts/webkitpy/common/net/layouttestresults.py index 249ecc9..a0e8ae4 100644 --- a/Tools/Scripts/webkitpy/common/net/layouttestresults.py +++ b/Tools/Scripts/webkitpy/common/net/layouttestresults.py @@ -134,6 +134,19 @@ class LayoutTestResults(object): def __init__(self, test_results): self._test_results = test_results + self._failure_limit_count = None + + # FIXME: run-webkit-tests should store the --exit-after-N-failures value + # (or some indication of early exit) somewhere in the results.html/results.json + # file. Until it does, callers should set the limit to + # --exit-after-N-failures value used in that run. Consumers of LayoutTestResults + # may use that value to know if absence from the failure list means PASS. + # https://bugs.webkit.org/show_bug.cgi?id=58481 + def set_failure_limit_count(self, limit): + self._failure_limit_count = limit + + def failure_limit_count(self): + return self._failure_limit_count def test_results(self): return self._test_results diff --git a/Tools/Scripts/webkitpy/common/net/layouttestresults_unittest.py b/Tools/Scripts/webkitpy/common/net/layouttestresults_unittest.py index 01b91b8..d25ad02 100644 --- a/Tools/Scripts/webkitpy/common/net/layouttestresults_unittest.py +++ b/Tools/Scripts/webkitpy/common/net/layouttestresults_unittest.py @@ -61,6 +61,12 @@ class LayoutTestResultsTest(unittest.TestCase): </html> """ + def test_set_failure_limit_count(self): + results = LayoutTestResults([]) + self.assertEquals(results.failure_limit_count(), None) + results.set_failure_limit_count(10) + self.assertEquals(results.failure_limit_count(), 10) + def test_parse_layout_test_results(self): failures = [test_failures.FailureMissingResult(), test_failures.FailureMissingImageHash(), test_failures.FailureMissingImage()] testname = 'fast/repaint/no-caret-repaint-in-non-content-editable-element.html' diff --git a/Tools/Scripts/webkitpy/common/net/statusserver.py b/Tools/Scripts/webkitpy/common/net/statusserver.py index abd298a..9622c89 100644 --- a/Tools/Scripts/webkitpy/common/net/statusserver.py +++ b/Tools/Scripts/webkitpy/common/net/statusserver.py @@ -25,6 +25,8 @@ # 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. +# +# This the client designed to talk to Tools/QueueStatusServer. from webkitpy.common.net.networktransaction import NetworkTransaction from webkitpy.common.system.deprecated_logging import log @@ -39,6 +41,7 @@ _log = logging.getLogger("webkitpy.common.net.statusserver") class StatusServer: + # FIXME: This should probably move to common.config.urls. default_host = "queues.webkit.org" def __init__(self, host=default_host, browser=None, bot_id=None): diff --git a/Tools/Scripts/webkitpy/common/system/executive.py b/Tools/Scripts/webkitpy/common/system/executive.py index 02619db..7d198dd 100644 --- a/Tools/Scripts/webkitpy/common/system/executive.py +++ b/Tools/Scripts/webkitpy/common/system/executive.py @@ -45,6 +45,7 @@ import sys import time from webkitpy.common.system.deprecated_logging import tee +from webkitpy.common.system.filesystem import FileSystem from webkitpy.python24 import versioning @@ -179,6 +180,22 @@ class Executive(object): # machines. return 2 + @staticmethod + def interpreter_for_script(script_path, fs=FileSystem()): + lines = fs.read_text_file(script_path).splitlines() + if not len(lines): + return None + first_line = lines[0] + if not first_line.startswith('#!'): + return None + if first_line.find('python') > -1: + return sys.executable + if first_line.find('perl') > -1: + return 'perl' + if first_line.find('ruby') > -1: + return 'ruby' + return None + def kill_process(self, pid): """Attempts to kill the given pid. Will fail silently if pid does not exist or insufficient permisssions.""" diff --git a/Tools/Scripts/webkitpy/common/system/executive_unittest.py b/Tools/Scripts/webkitpy/common/system/executive_unittest.py index 1dadc36..9a14d6b 100644 --- a/Tools/Scripts/webkitpy/common/system/executive_unittest.py +++ b/Tools/Scripts/webkitpy/common/system/executive_unittest.py @@ -34,6 +34,7 @@ import sys import unittest from webkitpy.common.system.executive import Executive, run_command, ScriptError +from webkitpy.common.system.filesystem_mock import MockFileSystem from webkitpy.test import cat, echo @@ -65,6 +66,33 @@ def never_ending_command(): class ExecutiveTest(unittest.TestCase): + def assert_interpreter_for_content(self, intepreter, content): + fs = MockFileSystem() + file_path = None + file_interpreter = None + + tempfile, temp_name = fs.open_binary_tempfile('') + tempfile.write(content) + tempfile.close() + file_interpreter = Executive.interpreter_for_script(temp_name, fs) + + self.assertEqual(file_interpreter, intepreter) + + def test_interpreter_for_script(self): + self.assert_interpreter_for_content(None, '') + self.assert_interpreter_for_content(None, 'abcd\nefgh\nijklm') + self.assert_interpreter_for_content(None, '##/usr/bin/perl') + self.assert_interpreter_for_content('perl', '#!/usr/bin/env perl') + self.assert_interpreter_for_content('perl', '#!/usr/bin/env perl\nfirst\nsecond') + self.assert_interpreter_for_content('perl', '#!/usr/bin/perl') + self.assert_interpreter_for_content('perl', '#!/usr/bin/perl -w') + self.assert_interpreter_for_content(sys.executable, '#!/usr/bin/env python') + self.assert_interpreter_for_content(sys.executable, '#!/usr/bin/env python\nfirst\nsecond') + self.assert_interpreter_for_content(sys.executable, '#!/usr/bin/python') + self.assert_interpreter_for_content('ruby', '#!/usr/bin/env ruby') + self.assert_interpreter_for_content('ruby', '#!/usr/bin/env ruby\nfirst\nsecond') + self.assert_interpreter_for_content('ruby', '#!/usr/bin/ruby') + def test_run_command_with_bad_command(self): def run_bad_command(): run_command(["foo_bar_command_blah"], error_handler=Executive.ignore_error, return_exit_code=True) diff --git a/Tools/Scripts/webkitpy/common/system/filesystem.py b/Tools/Scripts/webkitpy/common/system/filesystem.py index 1988546..58be03a 100644 --- a/Tools/Scripts/webkitpy/common/system/filesystem.py +++ b/Tools/Scripts/webkitpy/common/system/filesystem.py @@ -61,6 +61,10 @@ class FileSystem(object): """Wraps os.path.basename().""" return os.path.basename(path) + def chdir(self, path): + """Wraps os.chdir().""" + return os.chdir(path) + def copyfile(self, source, destination): """Copies the contents of the file at the given path to the destination path.""" @@ -108,6 +112,10 @@ class FileSystem(object): files.append(self.join(dirpath, filename)) return files + def getcwd(self): + """Wraps os.getcwd().""" + return os.getcwd() + def glob(self, path): """Wraps glob.glob().""" return glob.glob(path) diff --git a/Tools/Scripts/webkitpy/common/system/filesystem_mock.py b/Tools/Scripts/webkitpy/common/system/filesystem_mock.py index a6d158a..3be5854 100644 --- a/Tools/Scripts/webkitpy/common/system/filesystem_mock.py +++ b/Tools/Scripts/webkitpy/common/system/filesystem_mock.py @@ -35,7 +35,7 @@ from webkitpy.common.system import ospath class MockFileSystem(object): - def __init__(self, files=None): + def __init__(self, files=None, cwd='/'): """Initializes a "mock" filesystem that can be used to completely stub out a filesystem. @@ -48,6 +48,8 @@ class MockFileSystem(object): self.written_files = {} self._sep = '/' self.current_tmpno = 0 + self.cwd = cwd + self.dirs = {} def _get_sep(self): return self._sep @@ -61,13 +63,19 @@ class MockFileSystem(object): return path.rsplit(self.sep, 1) def abspath(self, path): - if path.endswith(self.sep): - return path[:-1] - return path + if os.path.isabs(path): + return self.normpath(path) + return self.abspath(self.join(self.cwd, path)) def basename(self, path): return self._split(path)[1] + def chdir(self, path): + path = self.normpath(path) + if not self.isdir(path): + raise OSError(errno.ENOENT, path, os.strerror(errno.ENOENT)) + self.cwd = path + def copyfile(self, source, destination): if not self.exists(source): self._raise_not_found(source) @@ -117,6 +125,9 @@ class MockFileSystem(object): return files + def getcwd(self, path): + return self.cwd + def glob(self, path): # FIXME: This only handles a wildcard '*' at the end of the path. # Maybe it should handle more? @@ -134,14 +145,18 @@ class MockFileSystem(object): def isdir(self, path): if path in self.files: return False - if not path.endswith(self.sep): - path += self.sep + path = self.normpath(path) + if path in self.dirs: + return True # We need to use a copy of the keys here in order to avoid switching # to a different thread and potentially modifying the dict in # mid-iteration. files = self.files.keys()[:] - return any(f.startswith(path) for f in files) + result = any(f.startswith(path) for f in files) + if result: + self.dirs[path] = True + return result def join(self, *comps): # FIXME: might want tests for this and/or a better comment about how @@ -204,8 +219,9 @@ class MockFileSystem(object): return TemporaryDirectory(fs=self, **kwargs) def maybe_make_directory(self, *path): - # FIXME: Implement such that subsequent calls to isdir() work? - pass + norm_path = self.normpath(self.join(*path)) + if not self.isdir(norm_path): + self.dirs[norm_path] = True def move(self, source, destination): if self.files[source] is None: @@ -216,7 +232,9 @@ class MockFileSystem(object): self.written_files[source] = None def normpath(self, path): - return path + # Like join(), relies on os.path functionality but normalizes the + # path separator to the mock one. + return re.sub(re.escape(os.path.sep), self.sep, os.path.normpath(path)) def open_binary_tempfile(self, suffix=''): path = self._mktemp(suffix) diff --git a/Tools/Scripts/webkitpy/common/system/filesystem_unittest.py b/Tools/Scripts/webkitpy/common/system/filesystem_unittest.py index 8455d72..8d4f0cb 100644 --- a/Tools/Scripts/webkitpy/common/system/filesystem_unittest.py +++ b/Tools/Scripts/webkitpy/common/system/filesystem_unittest.py @@ -48,6 +48,23 @@ class FileSystemTest(unittest.TestCase): self._missing_file = os.path.join(self._this_dir, 'missing_file.py') self._this_file = os.path.join(self._this_dir, 'filesystem_unittest.py') + def test_chdir(self): + fs = FileSystem() + cwd = fs.getcwd() + newdir = '/' + if sys.platform == 'win32': + newdir = 'c:\\' + fs.chdir(newdir) + self.assertEquals(fs.getcwd(), newdir) + fs.chdir(cwd) + + def test_chdir__notexists(self): + fs = FileSystem() + newdir = '/dirdoesnotexist' + if sys.platform == 'win32': + newdir = 'c:\\dirdoesnotexist' + self.assertRaises(OSError, fs.chdir, newdir) + def test_exists__true(self): fs = FileSystem() self.assertTrue(fs.exists(self._this_file)) @@ -56,6 +73,10 @@ class FileSystemTest(unittest.TestCase): fs = FileSystem() self.assertFalse(fs.exists(self._missing_file)) + def test_getcwd(self): + fs = FileSystem() + self.assertTrue(fs.exists(fs.getcwd())) + def test_isdir__true(self): fs = FileSystem() self.assertTrue(fs.isdir(self._this_dir)) diff --git a/Tools/Scripts/webkitpy/common/system/user.py b/Tools/Scripts/webkitpy/common/system/user.py index b79536c..aecb6ec 100644 --- a/Tools/Scripts/webkitpy/common/system/user.py +++ b/Tools/Scripts/webkitpy/common/system/user.py @@ -26,6 +26,7 @@ # (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 getpass import logging import os import re @@ -65,6 +66,10 @@ class User(object): return response @classmethod + def prompt_password(cls, message, repeat=1): + return cls.prompt(message, repeat=repeat, raw_input=getpass.getpass) + + @classmethod def prompt_with_list(cls, list_title, list_items, can_choose_multiple=False, raw_input=raw_input): print list_title i = 0 diff --git a/Tools/Scripts/webkitpy/layout_tests/layout_package/dump_render_tree_thread.py b/Tools/Scripts/webkitpy/layout_tests/layout_package/dump_render_tree_thread.py deleted file mode 100644 index 6d5cda8..0000000 --- a/Tools/Scripts/webkitpy/layout_tests/layout_package/dump_render_tree_thread.py +++ /dev/null @@ -1,226 +0,0 @@ -#!/usr/bin/env python -# Copyright (C) 2010 Google Inc. All rights reserved. -# Copyright (C) 2010 Gabor Rapcsanyi (rgabor@inf.u-szeged.hu), University of Szeged -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are -# met: -# -# * Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# * 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. -# * Neither the name of Google Inc. 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 THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT -# OWNER OR 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. - -"""This module implements a shared-memory, thread-based version of the worker -task in new-run-webkit-tests: it receives a list of tests from TestShellThread -and passes them one at a time to SingleTestRunner to execute.""" - -import logging -import Queue -import signal -import sys -import thread -import threading -import time - -from webkitpy.layout_tests.layout_package import worker_mixin - -_log = logging.getLogger("webkitpy.layout_tests.layout_package." - "dump_render_tree_thread") - - -class TestShellThread(threading.Thread, worker_mixin.WorkerMixin): - def __init__(self, port, options, worker_number, worker_name, - filename_list_queue, result_queue): - """Initialize all the local state for this DumpRenderTree thread. - - Args: - port: interface to port-specific hooks - options: command line options argument from optparse - worker_number: identifier for a particular worker thread. - worker_name: for logging. - filename_list_queue: A thread safe Queue class that contains lists - of tuples of (filename, uri) pairs. - result_queue: A thread safe Queue class that will contain - serialized TestResult objects. - """ - threading.Thread.__init__(self) - self._canceled = False - self._exception_info = None - self._next_timeout = None - self._thread_id = None - self._port = port - self._options = options - self._worker_number = worker_number - self._name = worker_name - self._filename_list_queue = filename_list_queue - self._result_queue = result_queue - self._current_group = None - self._filename_list = [] - self._test_group_timing_stats = {} - self._test_results = [] - self._num_tests = 0 - self._start_time = 0 - self._stop_time = 0 - self._http_lock_wait_begin = 0 - self._http_lock_wait_end = 0 - - def cancel(self): - """Set a flag telling this thread to quit.""" - self._canceled = True - - def clear_next_timeout(self): - """Mark a flag telling this thread to stop setting timeouts.""" - self._timeout = 0 - - def exception_info(self): - """If run() terminated on an uncaught exception, return it here - ((type, value, traceback) tuple). - Returns None if run() terminated normally. Meant to be called after - joining this thread.""" - return self._exception_info - - def id(self): - """Return a thread identifier.""" - return self._thread_id - - def next_timeout(self): - """Return the time the test is supposed to finish by.""" - if self._next_timeout: - return self._next_timeout + self._http_lock_wait_time() - return self._next_timeout - - def get_test_group_timing_stats(self): - """Returns a dictionary mapping test group to a tuple of - (number of tests in that group, time to run the tests)""" - return self._test_group_timing_stats - - def get_test_results(self): - """Return the list of all tests run on this thread. - - This is used to calculate per-thread statistics. - - """ - return self._test_results - - def get_total_time(self): - return max(self._stop_time - self._start_time - - self._http_lock_wait_time(), 0.0) - - def get_num_tests(self): - return self._num_tests - - def run(self): - """Delegate main work to a helper method and watch for uncaught - exceptions.""" - - self._covered_run() - - def _covered_run(self): - # FIXME: this is a separate routine to work around a bug - # in coverage: see http://bitbucket.org/ned/coveragepy/issue/85. - self._thread_id = thread.get_ident() - self._start_time = time.time() - self._num_tests = 0 - try: - _log.debug('%s starting' % (self.getName())) - self._run(test_runner=None, result_summary=None) - _log.debug('%s done (%d tests)' % (self.getName(), - self.get_num_tests())) - except KeyboardInterrupt: - self._exception_info = sys.exc_info() - _log.debug("%s interrupted" % self.getName()) - except: - # Save the exception for our caller to see. - self._exception_info = sys.exc_info() - self._stop_time = time.time() - _log.error('%s dying, exception raised' % self.getName()) - - self._stop_time = time.time() - - def run_in_main_thread(self, test_runner, result_summary): - """This hook allows us to run the tests from the main thread if - --num-test-shells==1, instead of having to always run two or more - threads. This allows us to debug the test harness without having to - do multi-threaded debugging.""" - self._run(test_runner, result_summary) - - def _http_lock_wait_time(self): - """Return the time what http locking takes.""" - if self._http_lock_wait_begin == 0: - return 0 - if self._http_lock_wait_end == 0: - return time.time() - self._http_lock_wait_begin - return self._http_lock_wait_end - self._http_lock_wait_begin - - def _run(self, test_runner, result_summary): - """Main work entry point of the thread. Basically we pull urls from the - filename queue and run the tests until we run out of urls. - - If test_runner is not None, then we call test_runner.UpdateSummary() - with the results of each test.""" - - # Initialize the real state of the WorkerMixin now that we're executing - # in the child thread. Technically, we could have called this during - # __init__(), but we wait until now to match Worker.run(). - self.safe_init(self._port) - - while True: - if self._canceled: - _log.debug('Testing cancelled') - self.cleanup() - return - - if len(self._filename_list) is 0: - if self._current_group is not None: - self._test_group_timing_stats[self._current_group] = \ - (self._num_tests_in_current_group, - time.time() - self._current_group_start_time) - - try: - self._current_group, self._filename_list = \ - self._filename_list_queue.get_nowait() - except Queue.Empty: - self.cleanup() - return - - if self._current_group == "tests_to_http_lock": - self._http_lock_wait_begin = time.time() - self.start_servers_with_lock() - self._http_lock_wait_end = time.time() - elif self._has_http_lock: - self.stop_servers_with_lock() - - self._num_tests_in_current_group = len(self._filename_list) - self._current_group_start_time = time.time() - - test_input = self._filename_list.pop(0) - - # We have a url, run tests. - self._num_tests += 1 - - result = self.run_test_with_timeout(test_input, self.timeout(test_input)) - - self.clean_up_after_test(test_input, result) - self._test_results.append(result) - self._result_queue.put(result.dumps()) - - if test_runner: - test_runner.update_summary(result_summary) diff --git a/Tools/Scripts/webkitpy/layout_tests/layout_package/json_layout_results_generator.py b/Tools/Scripts/webkitpy/layout_tests/layout_package/json_layout_results_generator.py index 19b02e8..dbb16c0 100644 --- a/Tools/Scripts/webkitpy/layout_tests/layout_package/json_layout_results_generator.py +++ b/Tools/Scripts/webkitpy/layout_tests/layout_package/json_layout_results_generator.py @@ -50,6 +50,7 @@ class JSONLayoutResultsGenerator(json_results_generator.JSONResultsGeneratorBase test_expectations.IMAGE: "I", test_expectations.TEXT: "F", test_expectations.MISSING: "O", + test_expectations.AUDIO: "A", test_expectations.IMAGE_PLUS_TEXT: "Z"} def __init__(self, port, builder_name, build_name, build_number, diff --git a/Tools/Scripts/webkitpy/layout_tests/layout_package/json_results.html b/Tools/Scripts/webkitpy/layout_tests/layout_package/json_results.html new file mode 100644 index 0000000..33aa04a --- /dev/null +++ b/Tools/Scripts/webkitpy/layout_tests/layout_package/json_results.html @@ -0,0 +1,555 @@ +<!DocType html> +<style> +body { + margin: 4px; +} + +body > p:first-of-type { + margin-top: 0; +} + +tr:first-of-type:hover { + opacity: 0.7 +} + +thead, tbody { + background-color: #E3E9FF; +} + +td { + padding: 0 4px; +} + +th:empty, td:empty { + padding: 0; +} + +th { + -webkit-user-select: none; + -moz-user-select: none; +} + +label { + margin-left: 10px; +} + +.results-row { + background-color: white; +} + +.results-row iframe { + width: 800px; + height: 600px; +} + +#options { + position: absolute; + top: 4px; + right: 4px; +} + +.expand-button { + background-color: white; + color: blue; + width: 11px; + height: 11px; + border: 1px solid blue; + display: inline-block; + margin: 0 3px 0 0; + position: relative; +} + +.expand-button-text { + position: absolute; + top: -0.3em; + left: 1px; +} + +.result-container { + display: inline-block; + border: 1px solid gray; +} + +.result-container iframe, .result-container img { + border: 0; + border-top: 1px solid lightgray; + vertical-align: top; +} + +.label { + padding-left: 3px; + font-weight: bold; + font-size: small; +} + +.pixel-zoom-container { + position: fixed; + top: 0; + left: 0; + width: 100%; + display: -webkit-box; +} + +.pixel-zoom-container > * { + display: -webkit-box; + -webkit-box-flex: 1; + border: 1px inset lightgray; + height: 100px; + overflow: hidden; + zoom: 300%; + background-color: white; +} + +.pixel-zoom-container img { + width: 800px; + height: 600px; + vertical-align: top; +} +</style> + +<script> +var g_results; +function ADD_RESULTS(input) +{ + g_results = input; +} +</script> + +<script src="full_results.json"></script> + +<script> +function stripExtension(test) +{ + var index = test.lastIndexOf('.'); + return test.substring(0, index); +} + +function parentOfType(node, selector) +{ + while (node = node.parentElement) { + if (node.webkitMatchesSelector(selector)) + return node; + } + return null; +} + +function appendResultIframe(src, parent) +{ + // FIXME: use audio tags for AUDIO tests? + var layoutTestsIndex = src.indexOf('LayoutTests'); + var name; + if (layoutTestsIndex != -1) { + var hasTrac = src.indexOf('trac.webkit.org') != -1; + var prefix = hasTrac ? 'trac.webkit.org/.../' : ''; + name = prefix + src.substring(layoutTestsIndex + 'LayoutTests/'.length); + } else { + var lastDashIndex = src.lastIndexOf('-pretty'); + if (lastDashIndex == -1) + lastDashIndex = src.lastIndexOf('-'); + name = src.substring(lastDashIndex + 1); + } + + var tagName = (src.lastIndexOf('.png') == -1) ? 'iframe' : 'img'; + + var container = document.createElement('div'); + container.className = 'result-container'; + container.innerHTML = '<div class=label>' + name + '</div><' + tagName + ' src="' + src + '?format=txt"></' + tagName + '>'; + parent.appendChild(container); +} + +function expandExpectations(e) +{ + var expandLink = e.target; + if (expandLink.className != 'expand-button-text') + expandLink = expandLink.querySelector('.expand-button-text'); + + var isExpand = expandLink.textContent == '+'; + var row = parentOfType(expandLink, 'tr'); + var parentTbody = row.parentNode; + var existingResultsRow = parentTbody.querySelector('.results-row'); + + if (!isExpand) { + expandLink.textContent = '+'; + existingResultsRow.style.display = 'none'; + return; + } + + var enDash = '\u2013'; + expandLink.textContent = enDash; + if (existingResultsRow) { + existingResultsRow.style.display = ''; + return; + } + + var newRow = document.createElement('tr'); + newRow.className = 'results-row'; + var newCell = document.createElement('td'); + newCell.colSpan = row.querySelectorAll('td').length; + + appendResultIframe(row.querySelector('.test-link').href, newCell); + + var resultLinks = row.querySelectorAll('.result-link'); + for (var i = 0; i < resultLinks.length; i++) + appendResultIframe(resultLinks[i].href, newCell); + + newRow.appendChild(newCell); + parentTbody.appendChild(newRow); +} + +function testLink(test) +{ + var basePath; + if (g_results.layout_tests_dir && location.toString().indexOf('file://') == 0) + basePath = g_results.layout_tests_dir + '/'; + else + basePath = 'http://trac.webkit.org/browser/trunk/LayoutTests/'; + return '<span class=expand-button onclick="expandExpectations(event)"><span class=expand-button-text>+</span></span>' + + '<a class=test-link href="' + basePath + test + '">' + test + '</a>'; +} + +function resultLink(testPrefix, suffix, contents) +{ + return '<a class=result-link href="' + testPrefix + suffix + '">' + contents + '</a> '; +} + +var g_hasTextFailures = false; +var g_hasImageFailures = false; + +var g_testsWithStderr = []; +var g_newTests = []; +var g_hasHttpTests = false; + +function tableRows() +{ + var html = ''; + for (var test in g_results.tests) { + if (g_results.tests[test].has_stderr) + g_testsWithStderr.push(test); + + g_hasHttpTests = g_hasHttpTests || test.indexOf('http/') == 0; + + var actual = g_results.tests[test].actual; + if (actual == 'MISSING') { + // FIXME: make sure that new-run-webkit-tests spits out an -actual.txt file for + // tests with MISSING results. + g_newTests.push(test); + continue; + } + + var expected = g_results.tests[test].expected || 'PASS'; + if (actual == 'PASS' && (!g_results.uses_expectations_file || expected == 'PASS')) + continue; + + // FIXME: put unexpected passes in a separate table. + + var row = '<td>' + testLink(test) + '</td>'; + var test_prefix = stripExtension(test); + + row += '<td>'; + if (actual == 'CRASH') + row += resultLink(test_prefix, '-stack.txt', 'stack'); + else if (actual == 'AUDIO') { + row += resultLink(test_prefix, '-expected.wav', 'expected'); + row += resultLink(test_prefix, '-actual.wav', 'actual'); + } else if (actual.indexOf('TEXT') != -1 || actual == 'TIMEOUT') { + // FIXME: only include timeout actual/expected results here if we actually spit out results for timeout tests. + g_hasTextFailures = true; + row += resultLink(test_prefix, '-expected.txt', 'expected') + + resultLink(test_prefix, '-actual.txt', 'actual') + + resultLink(test_prefix, '-diff.txt', 'diff'); + + if (g_results.has_pretty_patch) + row += resultLink(test_prefix, '-pretty-diff.html', 'pretty diff'); + + if (g_results.has_wdiff) + row += resultLink(test_prefix, '-wdiff.html', 'wdiff'); + } + + row += '</td><td>'; + + if (actual.indexOf('IMAGE') != -1) { + g_hasImageFailures = true; + + if (g_results.tests[test].is_mismatch_reftest) { + row += resultLink(test_prefix, '-expected-mismatch.html', 'ref mismatch html') + + resultLink(test_prefix, '-actual.png', 'actual'); + } else { + if (g_results.tests[test].is_reftest) + row += resultLink(test_prefix, '-expected.html', 'ref html'); + + row += resultLink(test_prefix, '-expected.png', 'expected') + + resultLink(test_prefix, '-actual.png', 'actual') + + resultLink(test_prefix, '-diff.png', 'diff'); + } + } + + row += '</td>'; + row += '<td>' + actual + '</td>'; + + if (g_results.uses_expectations_file) + row += '<td>' + expected + '</td>'; + + var isExpected = actual == 'SKIP'; + if (!isExpected && g_results.uses_expectations_file) { + var expectedArray = expected.split(' '); + if (expectedArray.indexOf(actual) != -1) + isExpected = true; + else if (expectedArray.indexOf('FAIL') != -1) + isExpected = actual == 'IMAGE' || actual == 'TEXT' || actual == 'IMAGE+TEXT'; + } + html += '<tbody class="' + (isExpected ? 'expected' : '') + '"><tr>' + row + '</tr></tbody>'; + } + return html; +} + +var html = ''; +if (g_results.uses_expectations_file) + html += '<div id=options><label><input class="unexpected-results" type=checkbox checked>Only show unexpected results</label></div>'; + +var tableRowsHtml = tableRows(); + +if (tableRowsHtml) { + html += '<p>Tests where results did not match expected results:</p>' + + '<table id="results-table"><thead><tr>' + + '<th>test</th>' + + '<th id="text-results-header">text results</th>' + + '<th id="image-results-header">image results</th>' + + '<th>failure type</th>'; + + if (g_results.uses_expectations_file) + html += '<th>expected failure type</th>'; + + html += '</tr></thead>' + tableRowsHtml + '</table>'; +} + +function appendTestList(tests, header, tableId, fileSuffix, linkName) +{ + tests.sort(); + + html += '<p>' + header + '</p><table id="' + tableId + '">'; + for (var i = 0; i < tests.length; i++) { + var test = tests[i]; + html += '<tbody><tr><td>' + testLink(test) + '</td><td>'; + + if (fileSuffix.indexOf('actual') == -1) + html += resultLink(stripExtension(test), fileSuffix, linkName); + else { + var testObject = g_results.tests[test]; + if (testObject.is_missing_audio) + html += resultLink(stripExtension(test), '-actual.wav', 'audio result'); + if (testObject.is_missing_text) + html += resultLink(stripExtension(test), fileSuffix, linkName); + if (testObject.is_missing_image) + html += resultLink(stripExtension(test), '-actual.png', 'png result'); + } + + html += '</td></tr></tbody>'; + } + html += '</table>' +} + +if (g_newTests.length) + appendTestList(g_newTests, 'Tests that had no expected results (probably new):', 'new-tests-table', '-actual.txt', 'result'); + +if (g_testsWithStderr.length) + appendTestList(g_testsWithStderr, 'Tests that had stderr output:', 'stderr-table', '-stderr.txt', 'stderr'); + +if (g_hasHttpTests) { + html += '<p>httpd access log: <a href="access_log.txt">access_log.txt</a></p>' + + '<p>httpd error log: <a href="error_log.txt">error_log.txt</a></p>'; +} + +document.write(html); + +function toArray(nodeList) +{ + return Array.prototype.slice.call(nodeList); +} + +function trim(string) +{ + return string.replace(/^[\s\xa0]+|[\s\xa0]+$/g, ''); +} + +// Just a namespace for code management. +var TableSorter = {}; + +TableSorter._forwardArrow = '<svg style="width:10px;height:10px"><polygon points="0,0 10,0 5,10" style="fill:#aaa"></svg>'; + +TableSorter._backwardArrow = '<svg style="width:10px;height:10px"><polygon points="0,10 10,10 5,0" style="fill:#aaa"></svg>'; + +TableSorter._sortedContents = function(header, arrow) +{ + return arrow + ' ' + trim(header.textContent) + ' ' + arrow; +} + +TableSorter._updateHeaderClassNames = function(newHeader) +{ + var sortHeader = document.querySelector('.sortHeader'); + if (sortHeader) { + if (sortHeader == newHeader) { + var isAlreadyReversed = sortHeader.classList.contains('reversed'); + if (isAlreadyReversed) + sortHeader.classList.remove('reversed'); + else + sortHeader.classList.add('reversed'); + } else { + sortHeader.textContent = sortHeader.textContent; + sortHeader.classList.remove('sortHeader'); + sortHeader.classList.remove('reversed'); + } + } + + newHeader.classList.add('sortHeader'); +} + +TableSorter._textContent = function(tbodyRow, column) +{ + return tbodyRow.querySelectorAll('td')[column].textContent; +} + +TableSorter._sortRows = function(newHeader, reversed) +{ + var testsTable = document.getElementById('results-table'); + var headers = toArray(testsTable.querySelectorAll('th')); + var sortColumn = headers.indexOf(newHeader); + + var rows = toArray(testsTable.querySelectorAll('tbody')); + + rows.sort(function(a, b) { + // Only need to support lexicographic sort for now. + var aText = TableSorter._textContent(a, sortColumn); + var bText = TableSorter._textContent(b, sortColumn); + + // Forward sort equal values by test name. + if (sortColumn && aText == bText) { + var aTestName = TableSorter._textContent(a, 0); + var bTestName = TableSorter._textContent(b, 0); + if (aTestName == bTestName) + return 0; + return aTestName < bTestName ? -1 : 1; + } + + if (reversed) + return aText < bText ? 1 : -1; + else + return aText < bText ? -1 : 1; + }); + + for (var i = 0; i < rows.length; i++) + testsTable.appendChild(rows[i]); +} + +TableSorter.sortColumn = function(columnNumber) +{ + var newHeader = document.getElementById('results-table').querySelectorAll('th')[columnNumber]; + TableSorter._sort(newHeader); +} + +TableSorter.handleClick = function(e) +{ + var newHeader = e.target; + if (newHeader.localName != 'th') + return; + TableSorter._sort(newHeader); +} + +TableSorter._sort = function(newHeader) +{ + TableSorter._updateHeaderClassNames(newHeader); + + var reversed = newHeader.classList.contains('reversed'); + var sortArrow = reversed ? TableSorter._backwardArrow : TableSorter._forwardArrow; + newHeader.innerHTML = TableSorter._sortedContents(newHeader, sortArrow); + + TableSorter._sortRows(newHeader, reversed); +} + +if (document.getElementById('results-table')) + document.getElementById('results-table').addEventListener('click', TableSorter.handleClick, false); +TableSorter.sortColumn(0); + +var PixelZoomer = {}; + +PixelZoomer._createContainer = function(e) +{ + var tbody = parentOfType(e.target, 'tbody'); + var imageDiffLinks = tbody.querySelector('tr').querySelectorAll('a[href$=".png"]'); + + var container = document.createElement('div'); + container.className = 'pixel-zoom-container'; + + var html = ''; + for (var i = 0; i < imageDiffLinks.length; i++) + html += '<div class=zoom-image-container><img src="' + imageDiffLinks[i].href + '"></div>'; + + container.innerHTML = html; + document.body.appendChild(container); + + PixelZoomer._position(e); +} + +PixelZoomer._position = function(e) +{ + var pageX = e.clientX; + var pageY = e.clientY; + var targetLocation = e.target.getBoundingClientRect(); + var x = pageX - targetLocation.left; + var y = pageY - targetLocation.top; + + var zoomContainers = document.querySelectorAll('.pixel-zoom-container > .zoom-image-container'); + for (var i = 0; i < zoomContainers.length; i++) { + var container = zoomContainers[i]; + container.scrollLeft = x - container.offsetWidth / 2; + container.scrollTop = y - container.offsetHeight / 2; + } +} + +PixelZoomer.handleMouseMove = function(e) { + if (PixelZoomer._mouseMoveTimeout) + clearTimeout(PixelZoomer._mouseMoveTimeout); + + if (parentOfType(e.target, '.pixel-zoom-container')) + return; + + var container = document.querySelector('.pixel-zoom-container'); + if (!e.target.src || e.target.src.indexOf('.png') == -1) { + if (container) + container.parentNode.removeChild(container); + return; + } + + if (!container) { + PixelZoomer._mouseMoveTimeout = setTimeout(function() { + PixelZoomer._createContainer(e); + }, 200); + return; + } + + PixelZoomer._position(e); +} + +document.body.addEventListener('mousemove', PixelZoomer.handleMouseMove, false); + + +var unexpectedStyleNode = document.createElement('style'); +document.body.appendChild(unexpectedStyleNode); + +function updateExpectedResults() +{ + var checkBox = document.querySelector('.unexpected-results'); + if (!checkBox || checkBox.checked) + unexpectedStyleNode.innerText = '.expected { display: none; }'; + else + unexpectedStyleNode.innerText = ''; +} + +updateExpectedResults(); +if (document.querySelector('.unexpected-results')) + document.querySelector('.unexpected-results').addEventListener('change', updateExpectedResults, false); + +if (!g_hasTextFailures) + document.body.getElementById('text-results-header').textContent = ''; +if (!g_hasImageFailures) + document.body.getElementById('image-results-header').textContent = ''; +</script> diff --git a/Tools/Scripts/webkitpy/layout_tests/layout_package/manager_worker_broker.py b/Tools/Scripts/webkitpy/layout_tests/layout_package/manager_worker_broker.py index 4886c30..7ead483 100644..100755 --- a/Tools/Scripts/webkitpy/layout_tests/layout_package/manager_worker_broker.py +++ b/Tools/Scripts/webkitpy/layout_tests/layout_package/manager_worker_broker.py @@ -45,7 +45,9 @@ TestRunner2 --> _InlineManager ---> _InlineWorker <-> Worker import logging import optparse +import printing import Queue +import sys import thread import threading import time @@ -315,9 +317,15 @@ if multiprocessing: _log.error("%s (pid %d) is wedged on test %s" % (self.name, self.pid, test_name)) def run(self): - logging.basicConfig() - port_obj = port.get(self._platform_name, self._options) + options = self._options + port_obj = port.get(self._platform_name, options) + # FIXME: this won't work if the calling process is logging + # somewhere other than sys.stderr and sys.stdout, but I'm not sure + # if this will be an issue in practice. + printer = printing.Printer(port_obj, options, sys.stderr, sys.stdout, + int(options.child_processes), options.experimental_fully_parallel) self._client.run(port_obj) + printer.cleanup() class _MultiProcessWorkerConnection(_WorkerConnection): diff --git a/Tools/Scripts/webkitpy/layout_tests/layout_package/manager_worker_broker_unittest.py b/Tools/Scripts/webkitpy/layout_tests/layout_package/manager_worker_broker_unittest.py index c32f880..6919225 100644 --- a/Tools/Scripts/webkitpy/layout_tests/layout_package/manager_worker_broker_unittest.py +++ b/Tools/Scripts/webkitpy/layout_tests/layout_package/manager_worker_broker_unittest.py @@ -42,6 +42,7 @@ from webkitpy.common.system import outputcapture from webkitpy.layout_tests import port from webkitpy.layout_tests.layout_package import manager_worker_broker from webkitpy.layout_tests.layout_package import message_broker2 +from webkitpy.layout_tests.layout_package import printing # In order to reliably control when child workers are starting and stopping, # we use a pair of global variables to hold queues used for messaging. Ideally @@ -104,7 +105,10 @@ class _TestWorker(manager_worker_broker.AbstractWorker): def get_options(worker_model): - option_list = manager_worker_broker.runtime_options() + option_list = (manager_worker_broker.runtime_options() + + printing.print_options() + + [optparse.make_option("--experimental-fully-parallel", default=False), + optparse.make_option("--child-processes", default='2')]) parser = optparse.OptionParser(option_list=option_list) options, args = parser.parse_args(args=['--worker-model', worker_model]) return options diff --git a/Tools/Scripts/webkitpy/layout_tests/layout_package/message_broker.py b/Tools/Scripts/webkitpy/layout_tests/layout_package/message_broker.py deleted file mode 100644 index 66a7aa8..0000000 --- a/Tools/Scripts/webkitpy/layout_tests/layout_package/message_broker.py +++ /dev/null @@ -1,178 +0,0 @@ -# Copyright (C) 2010 Google 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: -# -# * Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# * 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. -# * Neither the name of Google Inc. 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 THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT -# OWNER OR 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. - -"""Module for handling messages, threads, processes, and concurrency for run-webkit-tests. - -Testing is accomplished by having a manager (TestRunner) gather all of the -tests to be run, and sending messages to a pool of workers (TestShellThreads) -to run each test. Each worker communicates with one driver (usually -DumpRenderTree) to run one test at a time and then compare the output against -what we expected to get. - -This modules provides a message broker that connects the manager to the -workers: it provides a messaging abstraction and message loops, and -handles launching threads and/or processes depending on the -requested configuration. -""" - -import logging -import time - -from webkitpy.common.system import stack_utils - -import dump_render_tree_thread - -_log = logging.getLogger(__name__) - - -def get(port, options): - """Return an instance of a WorkerMessageBroker.""" - worker_model = options.worker_model - if worker_model == 'old-inline': - return InlineBroker(port, options) - if worker_model == 'old-threads': - return MultiThreadedBroker(port, options) - raise ValueError('unsupported value for --worker-model: %s' % worker_model) - - -class _WorkerState(object): - def __init__(self, name): - self.name = name - self.thread = None - - -class WorkerMessageBroker(object): - def __init__(self, port, options): - self._port = port - self._options = options - self._num_workers = int(self._options.child_processes) - - # This maps worker names to their _WorkerState values. - self._workers = {} - - def _threads(self): - return tuple([w.thread for w in self._workers.values()]) - - def start_workers(self, test_runner): - """Starts up the pool of workers for running the tests. - - Args: - test_runner: a handle to the manager/TestRunner object - """ - self._test_runner = test_runner - for worker_number in xrange(self._num_workers): - worker = _WorkerState('worker-%d' % worker_number) - worker.thread = self._start_worker(worker_number, worker.name) - self._workers[worker.name] = worker - return self._threads() - - def _start_worker(self, worker_number, worker_name): - raise NotImplementedError - - def run_message_loop(self): - """Loop processing messages until done.""" - raise NotImplementedError - - def cancel_workers(self): - """Cancel/interrupt any workers that are still alive.""" - pass - - def cleanup(self): - """Perform any necessary cleanup on shutdown.""" - pass - - -class InlineBroker(WorkerMessageBroker): - def _start_worker(self, worker_number, worker_name): - # FIXME: Replace with something that isn't a thread. - thread = dump_render_tree_thread.TestShellThread(self._port, - self._options, worker_number, worker_name, - self._test_runner._current_filename_queue, - self._test_runner._result_queue) - # Note: Don't start() the thread! If we did, it would actually - # create another thread and start executing it, and we'd no longer - # be single-threaded. - return thread - - def run_message_loop(self): - thread = self._threads()[0] - thread.run_in_main_thread(self._test_runner, - self._test_runner._current_result_summary) - self._test_runner.update() - - -class MultiThreadedBroker(WorkerMessageBroker): - def _start_worker(self, worker_number, worker_name): - thread = dump_render_tree_thread.TestShellThread(self._port, - self._options, worker_number, worker_name, - self._test_runner._current_filename_queue, - self._test_runner._result_queue) - thread.start() - return thread - - def run_message_loop(self): - threads = self._threads() - wedged_threads = set() - - # Loop through all the threads waiting for them to finish. - some_thread_is_alive = True - while some_thread_is_alive: - some_thread_is_alive = False - t = time.time() - for thread in threads: - if thread.isAlive(): - if thread in wedged_threads: - continue - - some_thread_is_alive = True - next_timeout = thread.next_timeout() - if next_timeout and t > next_timeout: - stack_utils.log_thread_state(_log.error, thread.getName(), thread.id(), "is wedged") - thread.clear_next_timeout() - wedged_threads.add(thread) - - exception_info = thread.exception_info() - if exception_info is not None: - # Re-raise the thread's exception here to make it - # clear that testing was aborted. Otherwise, - # the tests that did not run would be assumed - # to have passed. - raise exception_info[0], exception_info[1], exception_info[2] - - self._test_runner.update() - - if some_thread_is_alive: - time.sleep(0.01) - - if wedged_threads: - _log.warning("All remaining threads are wedged, bailing out.") - - def cancel_workers(self): - threads = self._threads() - for thread in threads: - thread.cancel() diff --git a/Tools/Scripts/webkitpy/layout_tests/layout_package/message_broker_unittest.py b/Tools/Scripts/webkitpy/layout_tests/layout_package/message_broker_unittest.py deleted file mode 100644 index f4cb5d2..0000000 --- a/Tools/Scripts/webkitpy/layout_tests/layout_package/message_broker_unittest.py +++ /dev/null @@ -1,161 +0,0 @@ -# Copyright (C) 2010 Google 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: -# -# * Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# * 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. -# * Neither the name of Google Inc. 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 THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT -# OWNER OR 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 logging -import Queue -import sys -import thread -import threading -import time -import unittest - -from webkitpy.common import array_stream -from webkitpy.common.system import outputcapture -from webkitpy.tool import mocktool - -from webkitpy.layout_tests import run_webkit_tests - -import message_broker - - -class TestThread(threading.Thread): - def __init__(self, started_queue, stopping_queue): - threading.Thread.__init__(self) - self._thread_id = None - self._started_queue = started_queue - self._stopping_queue = stopping_queue - self._timeout = False - self._timeout_queue = Queue.Queue() - self._exception_info = None - - def id(self): - return self._thread_id - - def getName(self): - return "worker-0" - - def run(self): - self._covered_run() - - def _covered_run(self): - # FIXME: this is a separate routine to work around a bug - # in coverage: see http://bitbucket.org/ned/coveragepy/issue/85. - self._thread_id = thread.get_ident() - try: - self._started_queue.put('') - msg = self._stopping_queue.get() - if msg == 'KeyboardInterrupt': - raise KeyboardInterrupt - elif msg == 'Exception': - raise ValueError() - elif msg == 'Timeout': - self._timeout = True - self._timeout_queue.get() - except: - self._exception_info = sys.exc_info() - - def exception_info(self): - return self._exception_info - - def next_timeout(self): - if self._timeout: - return time.time() - 10 - return time.time() - - def clear_next_timeout(self): - self._next_timeout = None - -class TestHandler(logging.Handler): - def __init__(self, astream): - logging.Handler.__init__(self) - self._stream = astream - - def emit(self, record): - self._stream.write(self.format(record)) - - -class MultiThreadedBrokerTest(unittest.TestCase): - class MockTestRunner(object): - def __init__(self): - pass - - def __del__(self): - pass - - def update(self): - pass - - def run_one_thread(self, msg): - runner = self.MockTestRunner() - port = None - options = mocktool.MockOptions(child_processes='1') - starting_queue = Queue.Queue() - stopping_queue = Queue.Queue() - broker = message_broker.MultiThreadedBroker(port, options) - broker._test_runner = runner - child_thread = TestThread(starting_queue, stopping_queue) - broker._workers['worker-0'] = message_broker._WorkerState('worker-0') - broker._workers['worker-0'].thread = child_thread - child_thread.start() - started_msg = starting_queue.get() - stopping_queue.put(msg) - res = broker.run_message_loop() - if msg == 'Timeout': - child_thread._timeout_queue.put('done') - child_thread.join(1.0) - self.assertFalse(child_thread.isAlive()) - return res - - def test_basic(self): - interrupted = self.run_one_thread('') - self.assertFalse(interrupted) - - def test_interrupt(self): - self.assertRaises(KeyboardInterrupt, self.run_one_thread, 'KeyboardInterrupt') - - def test_timeout(self): - # Because the timeout shows up as a wedged thread, this also tests - # log_wedged_worker(). - oc = outputcapture.OutputCapture() - stdout, stderr = oc.capture_output() - logger = message_broker._log - astream = array_stream.ArrayStream() - handler = TestHandler(astream) - logger.addHandler(handler) - interrupted = self.run_one_thread('Timeout') - stdout, stderr = oc.restore_output() - self.assertFalse(interrupted) - logger.handlers.remove(handler) - self.assertTrue('All remaining threads are wedged, bailing out.' in astream.get()) - - def test_exception(self): - self.assertRaises(ValueError, self.run_one_thread, 'Exception') - - -if __name__ == '__main__': - unittest.main() diff --git a/Tools/Scripts/webkitpy/layout_tests/layout_package/single_test_runner.py b/Tools/Scripts/webkitpy/layout_tests/layout_package/single_test_runner.py index a8c716f..c38cb8f 100644 --- a/Tools/Scripts/webkitpy/layout_tests/layout_package/single_test_runner.py +++ b/Tools/Scripts/webkitpy/layout_tests/layout_package/single_test_runner.py @@ -82,7 +82,7 @@ class SingleTestRunner: # For example, if 'foo.html' has two expectation files, 'foo-expected.html' and # 'foo-expected.txt', we should warn users. One test file must be used exclusively # in either layout tests or reftests, but not in both. - for suffix in ['.txt', '.checksum', '.png']: + for suffix in ('.txt', '.checksum', '.png', '.wav'): expected_filename = self._port.expected_filename(self._filename, suffix) if fs.exists(expected_filename): _log.error('The reftest (%s) can not have an expectation file (%s).' @@ -91,7 +91,8 @@ class SingleTestRunner: def _expected_driver_output(self): return base.DriverOutput(self._port.expected_text(self._filename), self._port.expected_image(self._filename), - self._port.expected_checksum(self._filename)) + self._port.expected_checksum(self._filename), + self._port.expected_audio(self._filename)) def _should_fetch_expected_checksum(self): return (self._options.pixel_tests and @@ -122,14 +123,14 @@ class SingleTestRunner: driver_output = self._driver.run_test(self._driver_input()) expected_driver_output = self._expected_driver_output() test_result = self._compare_output(driver_output, expected_driver_output) - test_result_writer.write_test_result(self._port, self._options.results_directory, self._filename, + test_result_writer.write_test_result(self._port, self._filename, driver_output, expected_driver_output, test_result.failures) return test_result def _run_rebaseline(self): driver_output = self._driver.run_test(self._driver_input()) failures = self._handle_error(driver_output) - test_result_writer.write_test_result(self._port, self._options.results_directory, self._filename, + test_result_writer.write_test_result(self._port, self._filename, driver_output, None, failures) # FIXME: It the test crashed or timed out, it might be bettter to avoid # to write new baselines. @@ -142,6 +143,9 @@ class SingleTestRunner: # DumpRenderTree may not output utf-8 text (e.g. webarchives). self._save_baseline_data(driver_output.text, ".txt", generate_new_baseline=self._options.new_baseline) + if driver_output.audio: + self._save_baseline_data(driver_output.audio, '.wav', + generate_new_baseline=self._options.new_baseline) if self._options.pixel_tests and driver_output.image_hash: self._save_baseline_data(driver_output.image, ".png", generate_new_baseline=self._options.new_baseline) @@ -190,7 +194,7 @@ class SingleTestRunner: failures = [] fs = self._port._filesystem if driver_output.timeout: - failures.append(test_failures.FailureTimeout(reference_filename)) + failures.append(test_failures.FailureTimeout(bool(reference_filename))) if reference_filename: testname = self._port.relative_test_filename(reference_filename) @@ -198,7 +202,7 @@ class SingleTestRunner: testname = self._testname if driver_output.crash: - failures.append(test_failures.FailureCrash(reference_filename)) + failures.append(test_failures.FailureCrash(bool(reference_filename))) _log.debug("%s Stacktrace for %s:\n%s" % (self._worker_name, testname, driver_output.error)) elif driver_output.error: @@ -216,19 +220,28 @@ class SingleTestRunner: return TestResult(self._filename, failures, driver_output.test_time) failures.extend(self._compare_text(driver_output.text, expected_driver_output.text)) + failures.extend(self._compare_audio(driver_output.audio, expected_driver_output.audio)) if self._options.pixel_tests: failures.extend(self._compare_image(driver_output, expected_driver_output)) return TestResult(self._filename, failures, driver_output.test_time) def _compare_text(self, actual_text, expected_text): failures = [] - if self._port.compare_text(self._get_normalized_output_text(actual_text), - # Assuming expected_text is already normalized. - expected_text): - if expected_text == '': - failures.append(test_failures.FailureMissingResult()) - else: - failures.append(test_failures.FailureTextMismatch()) + if (expected_text and actual_text and + # Assuming expected_text is already normalized. + self._port.compare_text(self._get_normalized_output_text(actual_text), expected_text)): + failures.append(test_failures.FailureTextMismatch()) + elif actual_text and not expected_text: + failures.append(test_failures.FailureMissingResult()) + return failures + + def _compare_audio(self, actual_audio, expected_audio): + failures = [] + if (expected_audio and actual_audio and + self._port.compare_audio(actual_audio, expected_audio)): + failures.append(test_failures.FailureAudioMismatch()) + elif actual_audio and not expected_audio: + failures.append(test_failures.FailureMissingAudio()) return failures def _get_normalized_output_text(self, output): @@ -259,7 +272,7 @@ class SingleTestRunner: base.DriverInput(self._reference_filename, self._timeout, driver_output1.image_hash)) test_result = self._compare_output_with_reference(driver_output1, driver_output2) - test_result_writer.write_test_result(self._port, self._options.results_directory, self._filename, + test_result_writer.write_test_result(self._port, self._filename, driver_output1, driver_output2, test_result.failures) return test_result diff --git a/Tools/Scripts/webkitpy/layout_tests/layout_package/test_expectations.py b/Tools/Scripts/webkitpy/layout_tests/layout_package/test_expectations.py index 132ccc2..a407ecc 100644 --- a/Tools/Scripts/webkitpy/layout_tests/layout_package/test_expectations.py +++ b/Tools/Scripts/webkitpy/layout_tests/layout_package/test_expectations.py @@ -41,8 +41,8 @@ _log = logging.getLogger("webkitpy.layout_tests.layout_package." "test_expectations") # Test expectation and modifier constants. -(PASS, FAIL, TEXT, IMAGE, IMAGE_PLUS_TEXT, TIMEOUT, CRASH, SKIP, WONTFIX, - SLOW, REBASELINE, MISSING, FLAKY, NOW, NONE) = range(15) +(PASS, FAIL, TEXT, IMAGE, IMAGE_PLUS_TEXT, AUDIO, TIMEOUT, CRASH, SKIP, WONTFIX, + SLOW, REBASELINE, MISSING, FLAKY, NOW, NONE) = range(16) # Test expectation file update action constants (NO_CHANGE, REMOVE_TEST, REMOVE_PLATFORM, ADD_PLATFORMS_EXCEPT_THIS) = range(4) @@ -120,7 +120,8 @@ class TestExpectations: self._expected_failures.get_test_set(REBASELINE, IMAGE) | self._expected_failures.get_test_set(REBASELINE, TEXT) | self._expected_failures.get_test_set(REBASELINE, - IMAGE_PLUS_TEXT)) + IMAGE_PLUS_TEXT) | + self._expected_failures.get_test_set(REBASELINE, AUDIO)) def get_options(self, test): return self._expected_failures.get_options(test) @@ -166,9 +167,8 @@ class TestExpectations: def has_modifier(self, test, modifier): return self._expected_failures.has_modifier(test, modifier) - def remove_platform_from_expectations(self, tests, platform): - return self._expected_failures.remove_platform_from_expectations( - tests, platform) + def remove_rebaselined_tests(self, tests): + return self._expected_failures.remove_rebaselined_tests(tests) def strip_comments(line): @@ -245,11 +245,11 @@ class TestExpectationsFile: Notes: -A test cannot be both SLOW and TIMEOUT - -A test should only be one of IMAGE, TEXT, IMAGE+TEXT, or FAIL. FAIL is - a migratory state that currently means either IMAGE, TEXT, or - IMAGE+TEXT. Once we have finished migrating the expectations, we will - change FAIL to have the meaning of IMAGE+TEXT and remove the IMAGE+TEXT - identifier. + -A test should only be one of IMAGE, TEXT, IMAGE+TEXT, AUDIO, or FAIL. + FAIL is a legacy value that currently means either IMAGE, + TEXT, or IMAGE+TEXT. Once we have finished migrating the expectations, + we should change FAIL to have the meaning of IMAGE+TEXT and remove the + IMAGE+TEXT identifier. -A test can be included twice, but not via the same path. -If a test is included twice, then the more precise path wins. -CRASH tests cannot be WONTFIX @@ -260,6 +260,7 @@ class TestExpectationsFile: 'text': TEXT, 'image': IMAGE, 'image+text': IMAGE_PLUS_TEXT, + 'audio': AUDIO, 'timeout': TIMEOUT, 'crash': CRASH, 'missing': MISSING} @@ -272,6 +273,7 @@ class TestExpectationsFile: IMAGE: ('image mismatch', 'image mismatch'), IMAGE_PLUS_TEXT: ('image and text mismatch', 'image and text mismatch'), + AUDIO: ('audio mismatch', 'audio mismatch'), CRASH: ('DumpRenderTree crash', 'DumpRenderTree crashes'), TIMEOUT: ('test timed out', 'tests timed out'), @@ -279,7 +281,7 @@ class TestExpectationsFile: 'no expected results found')} EXPECTATION_ORDER = (PASS, CRASH, TIMEOUT, MISSING, IMAGE_PLUS_TEXT, - TEXT, IMAGE, FAIL, SKIP) + TEXT, IMAGE, AUDIO, FAIL, SKIP) BUILD_TYPES = ('debug', 'release') @@ -436,75 +438,14 @@ class TestExpectationsFile: def get_non_fatal_errors(self): return self._non_fatal_errors - def remove_platform_from_expectations(self, tests, platform): - """Returns a copy of the expectations with the tests matching the - platform removed. - - If a test is in the test list and has an option that matches the given - platform, remove the matching platform and save the updated test back - to the file. If no other platforms remaining after removal, delete the - test from the file. - - Args: - tests: list of tests that need to update.. - platform: which platform option to remove. - - Returns: - the updated string. - """ - - assert(platform) - f_orig = self._get_iterable_expectations(self._expectations) - f_new = [] - - tests_removed = 0 - tests_updated = 0 - lineno = 0 - for line in f_orig: - lineno += 1 - action = self._get_platform_update_action(line, lineno, tests, - platform) - assert(action in (NO_CHANGE, REMOVE_TEST, REMOVE_PLATFORM, - ADD_PLATFORMS_EXCEPT_THIS)) - if action == NO_CHANGE: - # Save the original line back to the file - _log.debug('No change to test: %s', line) - f_new.append(line) - elif action == REMOVE_TEST: - tests_removed += 1 - _log.info('Test removed: %s', line) - elif action == REMOVE_PLATFORM: - parts = line.split(':') - new_options = parts[0].replace(platform.upper() + ' ', '', 1) - new_line = ('%s:%s' % (new_options, parts[1])) - f_new.append(new_line) - tests_updated += 1 - _log.info('Test updated: ') - _log.info(' old: %s', line) - _log.info(' new: %s', new_line) - elif action == ADD_PLATFORMS_EXCEPT_THIS: - parts = line.split(':') - _log.info('Test updated: ') - _log.info(' old: %s', line) - for p in self._port.test_platform_names(): - p = p.upper() - # This is a temp solution for rebaselining tool. - # Do not add tags WIN-7 and WIN-VISTA to test expectations - # if the original line does not specify the platform - # option. - # TODO(victorw): Remove WIN-VISTA and WIN-WIN7 once we have - # reliable Win 7 and Win Vista buildbots setup. - if not p in (platform.upper(), 'WIN-VISTA', 'WIN-WIN7'): - new_options = parts[0] + p + ' ' - new_line = ('%s:%s' % (new_options, parts[1])) - f_new.append(new_line) - _log.info(' new: %s', new_line) - tests_updated += 1 - - _log.info('Total tests removed: %d', tests_removed) - _log.info('Total tests updated: %d', tests_updated) - - return "".join(f_new) + def remove_rebaselined_tests(self, tests): + """Returns a copy of the expectations with the tests removed.""" + lines = [] + for (lineno, line) in enumerate(self._get_iterable_expectations(self._expectations)): + test, options, _ = self.parse_expectations_line(line, lineno) + if not (test and test in tests and 'rebaseline' in options): + lines.append(line) + return ''.join(lines) def parse_expectations_line(self, line, lineno): """Parses a line from test_expectations.txt and returns a tuple @@ -534,41 +475,6 @@ class TestExpectationsFile: return (test, options, expectations) - def _get_platform_update_action(self, line, lineno, tests, platform): - """Check the platform option and return the action needs to be taken. - - Args: - line: current line in test expectations file. - lineno: current line number of line - tests: list of tests that need to update.. - platform: which platform option to remove. - - Returns: - NO_CHANGE: no change to the line (comments, test not in the list etc) - REMOVE_TEST: remove the test from file. - REMOVE_PLATFORM: remove this platform option from the test. - ADD_PLATFORMS_EXCEPT_THIS: add all the platforms except this one. - """ - test, options, expectations = self.parse_expectations_line(line, - lineno) - if not test or test not in tests: - return NO_CHANGE - - has_any_platform = False - for option in options: - if option in self._port.test_platform_names(): - has_any_platform = True - if not option == platform: - return REMOVE_PLATFORM - - # If there is no platform specified, then it means apply to all - # platforms. Return the action to add all the platforms except this - # one. - if not has_any_platform: - return ADD_PLATFORMS_EXCEPT_THIS - - return REMOVE_TEST - def _add_to_all_expectations(self, test, options, expectations): # Make all paths unix-style so the dashboard doesn't need to. test = test.replace('\\', '/') @@ -929,7 +835,7 @@ class ModifierMatcher(object): 'mac-leopard': ['mac', 'leopard'], 'win-xp': ['win', 'xp'], 'win-vista': ['win', 'vista'], - 'win-7': ['win', 'win7'], + 'win-win7': ['win', 'win7'], } # We don't include the "none" modifier because it isn't actually legal. diff --git a/Tools/Scripts/webkitpy/layout_tests/layout_package/test_expectations_unittest.py b/Tools/Scripts/webkitpy/layout_tests/layout_package/test_expectations_unittest.py index 05d805d..0833079 100644 --- a/Tools/Scripts/webkitpy/layout_tests/layout_package/test_expectations_unittest.py +++ b/Tools/Scripts/webkitpy/layout_tests/layout_package/test_expectations_unittest.py @@ -377,44 +377,23 @@ BUG_TEST WIN-XP : passes/text.html = TEXT class RebaseliningTest(Base): """Test rebaselining-specific functionality.""" - def assertRemove(self, platform, input_expectations, expected_expectations): + def assertRemove(self, input_expectations, tests, expected_expectations): self.parse_exp(input_expectations) - test = self.get_test('failures/expected/text.html') - actual_expectations = self._exp.remove_platform_from_expectations( - test, platform) + actual_expectations = self._exp.remove_rebaselined_tests(tests) self.assertEqual(expected_expectations, actual_expectations) + def test_remove(self): + self.assertRemove('BUGX REBASELINE : failures/expected/text.html = TEXT\n' + 'BUGY : failures/expected/image.html = IMAGE\n' + 'BUGZ REBASELINE : failures/expected/crash.html = CRASH\n', + ['failures/expected/text.html'], + 'BUGY : failures/expected/image.html = IMAGE\n' + 'BUGZ REBASELINE : failures/expected/crash.html = CRASH\n') + def test_no_get_rebaselining_failures(self): self.parse_exp(self.get_basic_expectations()) self.assertEqual(len(self._exp.get_rebaselining_failures()), 0) - def test_get_rebaselining_failures_expand(self): - self.parse_exp(""" -BUG_TEST REBASELINE : failures/expected/text.html = TEXT -""") - self.assertEqual(len(self._exp.get_rebaselining_failures()), 1) - - def test_remove_expand(self): - self.assertRemove('mac', - 'BUGX REBASELINE : failures/expected/text.html = TEXT\n', - 'BUGX REBASELINE WIN : failures/expected/text.html = TEXT\n' - 'BUGX REBASELINE WIN-XP : failures/expected/text.html = TEXT\n') - - def test_remove_mac_win(self): - self.assertRemove('mac', - 'BUGX REBASELINE MAC WIN : failures/expected/text.html = TEXT\n', - 'BUGX REBASELINE WIN : failures/expected/text.html = TEXT\n') - - def test_remove_mac_mac(self): - self.assertRemove('mac', - 'BUGX REBASELINE MAC : failures/expected/text.html = TEXT\n', - '') - - def test_remove_nothing(self): - self.assertRemove('mac', - '\n\n', - '\n\n') - class ModifierTests(unittest.TestCase): def setUp(self): diff --git a/Tools/Scripts/webkitpy/layout_tests/layout_package/test_failures.py b/Tools/Scripts/webkitpy/layout_tests/layout_package/test_failures.py index 1fad772..41f457c 100644 --- a/Tools/Scripts/webkitpy/layout_tests/layout_package/test_failures.py +++ b/Tools/Scripts/webkitpy/layout_tests/layout_package/test_failures.py @@ -54,7 +54,8 @@ def determine_result_type(failure_list): return test_expectations.TIMEOUT elif (FailureMissingResult in failure_types or FailureMissingImage in failure_types or - FailureMissingImageHash in failure_types): + FailureMissingImageHash in failure_types or + FailureMissingAudio in failure_types): return test_expectations.MISSING else: is_text_failure = FailureTextMismatch in failure_types @@ -62,12 +63,15 @@ def determine_result_type(failure_list): FailureImageHashMismatch in failure_types) is_reftest_failure = (FailureReftestMismatch in failure_types or FailureReftestMismatchDidNotOccur in failure_types) + is_audio_failure = (FailureAudioMismatch in failure_types) if is_text_failure and is_image_failure: return test_expectations.IMAGE_PLUS_TEXT elif is_text_failure: return test_expectations.TEXT elif is_image_failure or is_reftest_failure: return test_expectations.IMAGE + elif is_audio_failure: + return test_expectations.AUDIO else: raise ValueError("unclassifiable set of failures: " + str(failure_types)) @@ -99,152 +103,56 @@ class TestFailure(object): """Returns the string/JSON representation of a TestFailure.""" return cPickle.dumps(self) - def result_html_output(self, filename): - """Returns an HTML string to be included on the results.html page.""" - raise NotImplementedError - def should_kill_dump_render_tree(self): """Returns True if we should kill DumpRenderTree before the next test.""" return False - def relative_output_filename(self, filename, modifier): - """Returns a relative filename inside the output dir that contains - modifier. - - For example, if filename is fast\dom\foo.html and modifier is - "-expected.txt", the return value is fast\dom\foo-expected.txt - - Args: - filename: relative filename to test file - modifier: a string to replace the extension of filename with - - Return: - The relative windows path to the output filename - """ - # FIXME: technically this breaks if files don't use ".ext" to indicate - # the extension, but passing in a Filesystem object here is a huge - # hassle. - return filename[:filename.rfind('.')] + modifier - - -class ComparisonTestFailure(TestFailure): - """Base class that produces standard HTML output based on the result of the comparison test. - - Subclasses may commonly choose to override the ResultHtmlOutput, but still - use the standard OutputLinks. - """ - - # Filename suffixes used by ResultHtmlOutput. - OUT_FILENAMES = () - - def output_links(self, filename, out_names): - """Returns a string holding all applicable output file links. - - Args: - filename: the test filename, used to construct the result file names - out_names: list of filename suffixes for the files. If three or more - suffixes are in the list, they should be [actual, expected, diff, - wdiff]. Two suffixes should be [actual, expected], and a - single item is the [actual] filename suffix. - If out_names is empty, returns the empty string. - """ - # FIXME: Seems like a bad idea to separate the display name data - # from the path data by hard-coding the display name here - # and passing in the path information via out_names. - # - # FIXME: Also, we don't know for sure that these files exist, - # and we shouldn't be creating links to files that don't exist - # (for example, if we don't actually have wdiff output). - links = [''] - uris = [self.relative_output_filename(filename, fn) for - fn in out_names] - if len(uris) > 1: - links.append("<a href='%s'>expected</a>" % uris[1]) - if len(uris) > 0: - links.append("<a href='%s'>actual</a>" % uris[0]) - if len(uris) > 2: - links.append("<a href='%s'>diff</a>" % uris[2]) - if len(uris) > 3: - links.append("<a href='%s'>wdiff</a>" % uris[3]) - if len(uris) > 4: - links.append("<a href='%s'>pretty diff</a>" % uris[4]) - return ' '.join(links) - - def result_html_output(self, filename): - return self.message() + self.output_links(filename, self.OUT_FILENAMES) - class FailureTimeout(TestFailure): """Test timed out. We also want to restart DumpRenderTree if this happens.""" - - def __init__(self, reference_filename=None): - self.reference_filename = reference_filename + def __init__(self, is_reftest=False): + self.is_reftest = is_reftest @staticmethod def message(): return "Test timed out" - def result_html_output(self, filename): - if self.reference_filename: - return "<strong>%s</strong> (occured in <a href=%s>expected html</a>)" % ( - self.message(), self.reference_filename) - return "<strong>%s</strong>" % self.message() - def should_kill_dump_render_tree(self): return True class FailureCrash(TestFailure): """DumpRenderTree crashed.""" - - def __init__(self, reference_filename=None): - self.reference_filename = reference_filename + def __init__(self, is_reftest=False): + self.is_reftest = is_reftest @staticmethod def message(): return "DumpRenderTree crashed" - def result_html_output(self, filename): - # FIXME: create a link to the minidump file - stack = self.relative_output_filename(filename, "-stack.txt") - if self.reference_filename: - return "<strong>%s</strong> <a href=%s>stack</a> (occured in <a href=%s>expected html</a>)" % ( - self.message(), stack, self.reference_filename) - else: - return "<strong>%s</strong> <a href=%s>stack</a>" % (self.message(), stack) - def should_kill_dump_render_tree(self): return True -class FailureMissingResult(ComparisonTestFailure): +class FailureMissingResult(TestFailure): """Expected result was missing.""" - OUT_FILENAMES = ("-actual.txt",) @staticmethod def message(): return "No expected results found" - def result_html_output(self, filename): - return ("<strong>%s</strong>" % self.message() + - self.output_links(filename, self.OUT_FILENAMES)) - -class FailureTextMismatch(ComparisonTestFailure): +class FailureTextMismatch(TestFailure): """Text diff output failed.""" - # Filename suffixes used by ResultHtmlOutput. - # FIXME: Why don't we use the constants from TestTypeBase here? - OUT_FILENAMES = ("-actual.txt", "-expected.txt", "-diff.txt", - "-wdiff.html", "-pretty-diff.html") @staticmethod def message(): return "Text diff mismatch" -class FailureMissingImageHash(ComparisonTestFailure): +class FailureMissingImageHash(TestFailure): """Actual result hash was missing.""" # Chrome doesn't know to display a .checksum file as text, so don't bother # putting in a link to the actual result. @@ -253,26 +161,17 @@ class FailureMissingImageHash(ComparisonTestFailure): def message(): return "No expected image hash found" - def result_html_output(self, filename): - return "<strong>%s</strong>" % self.message() - -class FailureMissingImage(ComparisonTestFailure): +class FailureMissingImage(TestFailure): """Actual result image was missing.""" - OUT_FILENAMES = ("-actual.png",) @staticmethod def message(): return "No expected image found" - def result_html_output(self, filename): - return ("<strong>%s</strong>" % self.message() + - self.output_links(filename, self.OUT_FILENAMES)) - -class FailureImageHashMismatch(ComparisonTestFailure): +class FailureImageHashMismatch(TestFailure): """Image hashes didn't match.""" - OUT_FILENAMES = ("-actual.png", "-expected.png", "-diff.png") @staticmethod def message(): @@ -281,7 +180,7 @@ class FailureImageHashMismatch(ComparisonTestFailure): return "Image mismatch" -class FailureImageHashIncorrect(ComparisonTestFailure): +class FailureImageHashIncorrect(TestFailure): """Actual result hash is incorrect.""" # Chrome doesn't know to display a .checksum file as text, so don't bother # putting in a link to the actual result. @@ -290,45 +189,37 @@ class FailureImageHashIncorrect(ComparisonTestFailure): def message(): return "Images match, expected image hash incorrect. " - def result_html_output(self, filename): - return "<strong>%s</strong>" % self.message() - -class FailureReftestMismatch(ComparisonTestFailure): +class FailureReftestMismatch(TestFailure): """The result didn't match the reference rendering.""" - OUT_FILENAMES = ("-expected.html", "-expected.png", "-actual.png", - "-diff.png",) - @staticmethod def message(): return "Mismatch with reference" - def output_links(self, filename, out_names): - links = [''] - uris = [self.relative_output_filename(filename, output_filename) - for output_filename in out_names] - for text, uri in zip(['-expected.html', 'expected', 'actual', 'diff'], uris): - links.append("<a href='%s'>%s</a>" % (uri, text)) - return ' '.join(links) - -class FailureReftestMismatchDidNotOccur(ComparisonTestFailure): +class FailureReftestMismatchDidNotOccur(TestFailure): """Unexpected match between the result and the reference rendering.""" - OUT_FILENAMES = ("-expected-mismatch.html", "-actual.png",) - @staticmethod def message(): return "Mismatch with the reference did not occur" - def output_links(self, filename, out_names): - links = [''] - uris = [self.relative_output_filename(filename, output_filename) - for output_filename in out_names] - for text, uri in zip(['-expected-mismatch.html', 'image'], uris): - links.append("<a href='%s'>%s</a>" % (uri, text)) - return ' '.join(links) + +class FailureMissingAudio(TestFailure): + """Actual result image was missing.""" + + @staticmethod + def message(): + return "No expected audio found" + + +class FailureAudioMismatch(TestFailure): + """Audio files didn't match.""" + + @staticmethod + def message(): + return "Audio mismatch" # Convenient collection of all failure classes for anything that might diff --git a/Tools/Scripts/webkitpy/layout_tests/layout_package/test_failures_unittest.py b/Tools/Scripts/webkitpy/layout_tests/layout_package/test_failures_unittest.py index c5aa2d6..9b0576e 100644 --- a/Tools/Scripts/webkitpy/layout_tests/layout_package/test_failures_unittest.py +++ b/Tools/Scripts/webkitpy/layout_tests/layout_package/test_failures_unittest.py @@ -34,9 +34,6 @@ from webkitpy.layout_tests.layout_package.test_failures import * class Test(unittest.TestCase): - def assertResultHtml(self, failure_obj): - self.assertNotEqual(failure_obj.result_html_output('foo'), None) - def assert_loads(self, cls): failure_obj = cls() s = failure_obj.dumps() @@ -49,22 +46,22 @@ class Test(unittest.TestCase): self.assertFalse(failure_obj != new_failure_obj) def test_crash(self): - self.assertResultHtml(FailureCrash()) + FailureCrash() def test_hash_incorrect(self): - self.assertResultHtml(FailureImageHashIncorrect()) + FailureImageHashIncorrect() def test_missing(self): - self.assertResultHtml(FailureMissingResult()) + FailureMissingResult() def test_missing_image(self): - self.assertResultHtml(FailureMissingImage()) + FailureMissingImage() def test_missing_image_hash(self): - self.assertResultHtml(FailureMissingImageHash()) + FailureMissingImageHash() def test_timeout(self): - self.assertResultHtml(FailureTimeout()) + FailureTimeout() def test_unknown_failure_type(self): class UnknownFailure(TestFailure): @@ -73,8 +70,6 @@ class Test(unittest.TestCase): failure_obj = UnknownFailure() self.assertRaises(ValueError, determine_result_type, [failure_obj]) self.assertRaises(NotImplementedError, failure_obj.message) - self.assertRaises(NotImplementedError, failure_obj.result_html_output, - "foo.txt") def test_loads(self): for c in ALL_FAILURE_CLASSES: @@ -89,12 +84,5 @@ class Test(unittest.TestCase): crash_set = set([FailureCrash(), "FailureCrash"]) self.assertEqual(len(crash_set), 2) - def test_relative_output_filename(self): - # This could be any Failure* object, since we're testing a method - # on the base class. - failure_obj = FailureTextMismatch() - actual_filename = failure_obj.relative_output_filename("fast/html/article-element.html", "-actual.txt") - self.assertEquals(actual_filename, "fast/html/article-element-actual.txt") - if __name__ == '__main__': unittest.main() diff --git a/Tools/Scripts/webkitpy/layout_tests/layout_package/test_result_writer.py b/Tools/Scripts/webkitpy/layout_tests/layout_package/test_result_writer.py index e209503..07e6389 100644 --- a/Tools/Scripts/webkitpy/layout_tests/layout_package/test_result_writer.py +++ b/Tools/Scripts/webkitpy/layout_tests/layout_package/test_result_writer.py @@ -36,12 +36,16 @@ from webkitpy.layout_tests.layout_package import test_failures _log = logging.getLogger(__name__) -def write_test_result(port, root_output_dir, filename, driver_output, +def write_test_result(port, filename, driver_output, expected_driver_output, failures): """Write the test result to the result output directory.""" + root_output_dir = port.results_directory() checksums_mismatch_but_images_are_same = False imagehash_mismatch_failure = None writer = TestResultWriter(port, root_output_dir, filename) + if driver_output.error: + writer.write_stderr(driver_output.error) + for failure in failures: # FIXME: Instead of this long 'if' block, each failure class might # have a responsibility for writing a test result. @@ -63,8 +67,11 @@ def write_test_result(port, root_output_dir, filename, driver_output, if not images_are_different: checksums_mismatch_but_images_are_same = True imagehash_mismatch_failure = failure + elif isinstance(failure, (test_failures.FailureAudioMismatch, + test_failures.FailureMissingAudio)): + writer.write_audio_files(driver_output.audio, expected_driver_output.audio) elif isinstance(failure, test_failures.FailureCrash): - if failure.reference_filename: + if failure.is_reftest: writer.write_crash_report(expected_driver_output.error) else: writer.write_crash_report(driver_output.error) @@ -150,6 +157,12 @@ class TestResultWriter(object): if expected is not None: fs.write_binary_file(expected_filename, expected) + def write_stderr(self, error): + fs = self._port._filesystem + filename = self.output_filename("-stderr.txt") + fs.maybe_make_directory(fs.dirname(filename)) + fs.write_text_file(filename, error) + def write_crash_report(self, error): """Write crash information.""" fs = self._port._filesystem @@ -187,6 +200,9 @@ class TestResultWriter(object): pretty_patch_filename = self.output_filename(self.FILENAME_SUFFIX_PRETTY_PATCH) fs.write_binary_file(pretty_patch_filename, pretty_patch) + def write_audio_files(self, actual_audio, expected_audio): + self.write_output_files('.wav', actual_audio, expected_audio) + def write_image_files(self, actual_image, expected_image): self.write_output_files('.png', actual_image, expected_image) diff --git a/Tools/Scripts/webkitpy/layout_tests/layout_package/test_runner.py b/Tools/Scripts/webkitpy/layout_tests/layout_package/test_runner.py index 569dd51..8e534b1 100644 --- a/Tools/Scripts/webkitpy/layout_tests/layout_package/test_runner.py +++ b/Tools/Scripts/webkitpy/layout_tests/layout_package/test_runner.py @@ -46,10 +46,8 @@ import random import sys import time -from webkitpy.layout_tests.layout_package import dump_render_tree_thread from webkitpy.layout_tests.layout_package import json_layout_results_generator from webkitpy.layout_tests.layout_package import json_results_generator -from webkitpy.layout_tests.layout_package import message_broker from webkitpy.layout_tests.layout_package import printing from webkitpy.layout_tests.layout_package import test_expectations from webkitpy.layout_tests.layout_package import test_failures @@ -145,6 +143,29 @@ def summarize_results(port_obj, expectations, result_summary, retry_summary, tes tests[test] = {} tests[test]['expected'] = expected tests[test]['actual'] = " ".join(actual) + # FIXME: Set this correctly once https://webkit.org/b/37739 is fixed + # and only set it if there actually is stderr data. + tests[test]['has_stderr'] = False + + failure_types = [type(f) for f in result.failures] + if test_failures.FailureMissingAudio in failure_types: + tests[test]['is_missing_audio'] = True + + if test_failures.FailureReftestMismatch in failure_types: + tests[test]['is_reftest'] = True + + for f in result.failures: + if 'is_reftest' in result.failures: + tests[test]['is_reftest'] = True + + if test_failures.FailureReftestMismatchDidNotOccur in failure_types: + tests[test]['is_mismatch_reftest'] = True + + if test_failures.FailureMissingResult in failure_types: + tests[test]['is_missing_text'] = True + + if test_failures.FailureMissingImage in failure_types or test_failures.FailureMissingImageHash in failure_types: + tests[test]['is_missing_image'] = True if filename in test_timings_map: time_seconds = test_timings_map[filename] @@ -154,6 +175,12 @@ def summarize_results(port_obj, expectations, result_summary, retry_summary, tes results['num_passes'] = num_passes results['num_flaky'] = num_flaky results['num_regressions'] = num_regressions + # FIXME: If non-chromium ports start using an expectations file, + # we should make this check more robust. + results['uses_expectations_file'] = port_obj.name().find('chromium') != -1 + results['layout_tests_dir'] = port_obj.layout_tests_dir() + results['has_wdiff'] = port_obj.wdiff_available() + results['has_pretty_patch'] = port_obj.pretty_patch_available() return results @@ -205,6 +232,7 @@ class TestRunner: self._test_files_list = None self._result_queue = Queue.Queue() self._retrying = False + self._results_directory = self._port.results_directory() def collect_tests(self, args, last_unexpected_results): """Find all the files to test. @@ -355,8 +383,7 @@ class TestRunner: self._printer.print_expected(extra_msg) tests_run_msg += "\n" + extra_msg files.extend(test_files[0:extra]) - tests_run_filename = self._fs.join(self._options.results_directory, - "tests_run.txt") + tests_run_filename = self._fs.join(self._results_directory, "tests_run.txt") self._fs.write_text_file(tests_run_filename, tests_run_msg) len_skip_chunk = int(len(files) * len(skipped) / @@ -513,8 +540,16 @@ class TestRunner: return True return False - def _num_workers(self): - return int(self._options.child_processes) + def _num_workers(self, num_shards): + num_workers = min(int(self._options.child_processes), num_shards) + driver_name = self._port.driver_name() + if num_workers == 1: + self._printer.print_config("Running 1 %s over %s" % + (driver_name, grammar.pluralize('shard', num_shards))) + else: + self._printer.print_config("Running %d %ss in parallel over %d shards" % + (num_workers, driver_name, num_shards)) + return num_workers def _run_tests(self, file_list, result_summary): """Runs the tests in the file_list. @@ -532,54 +567,7 @@ class TestRunner: in the form {filename:filename, test_run_time:test_run_time} result_summary: summary object to populate with the results """ - - self._printer.print_update('Sharding tests ...') - num_workers = self._num_workers() - test_lists = self._shard_tests(file_list, - num_workers > 1 and not self._options.experimental_fully_parallel) - filename_queue = Queue.Queue() - for item in test_lists: - filename_queue.put(item) - - self._printer.print_update('Starting %s ...' % - grammar.pluralize('worker', num_workers)) - self._message_broker = message_broker.get(self._port, self._options) - broker = self._message_broker - self._current_filename_queue = filename_queue - self._current_result_summary = result_summary - - if not self._options.dry_run: - threads = broker.start_workers(self) - else: - threads = {} - - self._printer.print_update("Starting testing ...") - keyboard_interrupted = False - interrupted = False - if not self._options.dry_run: - try: - broker.run_message_loop() - except KeyboardInterrupt: - _log.info("Interrupted, exiting") - broker.cancel_workers() - keyboard_interrupted = True - interrupted = True - except TestRunInterruptedException, e: - _log.info(e.reason) - broker.cancel_workers() - interrupted = True - except: - # Unexpected exception; don't try to clean up workers. - _log.info("Exception raised, exiting") - raise - - thread_timings, test_timings, individual_test_timings = \ - self._collect_timing_info(threads) - - broker.cleanup() - self._message_broker = None - return (interrupted, keyboard_interrupted, thread_timings, test_timings, - individual_test_timings) + raise NotImplementedError() def update(self): self.update_summary(self._current_result_summary) @@ -629,7 +617,7 @@ class TestRunner: self._clobber_old_results() # Create the output directory if it doesn't already exist. - self._port.maybe_make_directory(self._options.results_directory) + self._port.maybe_make_directory(self._results_directory) self._port.setup_test_run() @@ -711,9 +699,9 @@ class TestRunner: # Write the summary to disk (results.html) and display it if requested. if not self._options.dry_run: - wrote_results = self._write_results_html_file(result_summary) - if self._options.show_results and wrote_results: - self._show_results_html_file() + self._copy_results_html_file() + if self._options.show_results: + self._show_results_html_file(result_summary) # Now that we've completed all the processing we can, we re-raise # a KeyboardInterrupt if necessary so the caller can handle it. @@ -773,13 +761,12 @@ class TestRunner: # files in the results directory are explicitly used for cross-run # tracking. self._printer.print_update("Clobbering old results in %s" % - self._options.results_directory) + self._results_directory) layout_tests_dir = self._port.layout_tests_dir() possible_dirs = self._port.test_dirs() for dirname in possible_dirs: if self._fs.isdir(self._fs.join(layout_tests_dir, dirname)): - self._fs.rmtree(self._fs.join(self._options.results_directory, - dirname)) + self._fs.rmtree(self._fs.join(self._results_directory, dirname)) def _get_failures(self, result_summary, include_crashes): """Filters a dict of results and returns only the failures. @@ -829,17 +816,17 @@ class TestRunner: individual_test_timings: list of test times (used by the flakiness dashboard). """ - _log.debug("Writing JSON files in %s." % self._options.results_directory) + _log.debug("Writing JSON files in %s." % self._results_directory) - unexpected_json_path = self._fs.join(self._options.results_directory, "unexpected_results.json") + unexpected_json_path = self._fs.join(self._results_directory, "unexpected_results.json") json_results_generator.write_json(self._fs, unexpected_results, unexpected_json_path) - full_results_path = self._fs.join(self._options.results_directory, "full_results.json") + full_results_path = self._fs.join(self._results_directory, "full_results.json") json_results_generator.write_json(self._fs, summarized_results, full_results_path) # Write a json file of the test_expectations.txt file for the layout # tests dashboard. - expectations_path = self._fs.join(self._options.results_directory, "expectations.json") + expectations_path = self._fs.join(self._results_directory, "expectations.json") expectations_json = \ self._expectations.get_expectations_json_for_all_platforms() self._fs.write_text_file(expectations_path, @@ -847,7 +834,7 @@ class TestRunner: generator = json_layout_results_generator.JSONLayoutResultsGenerator( self._port, self._options.builder_name, self._options.build_name, - self._options.build_number, self._options.results_directory, + self._options.build_number, self._results_directory, BUILDER_BASE_URL, individual_test_timings, self._expectations, result_summary, self._test_files_list, self._options.test_results_server, @@ -865,8 +852,7 @@ class TestRunner: p = self._printer p.print_config("Using port '%s'" % self._port.name()) p.print_config("Test configuration: %s" % self._port.test_configuration()) - p.print_config("Placing test results in %s" % - self._options.results_directory) + p.print_config("Placing test results in %s" % self._results_directory) if self._options.new_baseline: p.print_config("Placing new baselines in %s" % self._port.baseline_path()) @@ -880,12 +866,6 @@ class TestRunner: (self._options.time_out_ms, self._options.slow_time_out_ms)) - if self._num_workers() == 1: - p.print_config("Running one %s" % self._port.driver_name()) - else: - p.print_config("Running %s %ss in parallel" % - (self._options.child_processes, - self._port.driver_name())) p.print_config('Command line: ' + ' '.join(self._port.driver_cmd_line())) p.print_config("Worker model: %s" % self._options.worker_model) @@ -1136,67 +1116,25 @@ class TestRunner: self._printer.print_actual(" %5d %-24s (%4.1f%%)" % (len(results), desc[len(results) != 1], pct)) - def _results_html(self, test_files, failures, title="Test Failures", override_time=None): - """ - test_files = a list of file paths - failures = dictionary mapping test paths to failure objects - title = title printed at top of test - override_time = current time (used by unit tests) - """ - page = """<html> - <head> - <title>Layout Test Results (%(time)s)</title> - </head> - <body> - <h2>%(title)s (%(time)s)</h2> - """ % {'title': title, 'time': override_time or time.asctime()} - - for test_file in sorted(test_files): - test_name = self._port.relative_test_filename(test_file) - test_url = self._port.filename_to_uri(test_file) - page += u"<p><a href='%s'>%s</a><br />\n" % (test_url, test_name) - test_failures = failures.get(test_file, []) - for failure in test_failures: - page += (u" %s<br/>" % - failure.result_html_output(test_name)) - page += "</p>\n" - page += "</body></html>\n" - return page - - def _write_results_html_file(self, result_summary): - """Write results.html which is a summary of tests that failed. - - Args: - result_summary: a summary of the results :) + def _copy_results_html_file(self): + base_dir = self._port.path_from_webkit_base('Tools', 'Scripts', 'webkitpy', 'layout_tests', 'layout_package') + results_file = self._fs.join(base_dir, 'json_results.html') + # FIXME: What should we do if this doesn't exist (e.g., in unit tests)? + if self._fs.exists(results_file): + self._fs.copyfile(results_file, self._fs.join(self._results_directory, "results.html")) - Returns: - True if any results were written (since expected failures may be - omitted) - """ - # test failures + def _show_results_html_file(self, result_summary): + """Shows the results.html page.""" if self._options.full_results_html: - results_title = "Test Failures" test_files = result_summary.failures.keys() else: - results_title = "Unexpected Test Failures" - unexpected_failures = self._get_failures(result_summary, - include_crashes=True) + unexpected_failures = self._get_failures(result_summary, include_crashes=True) test_files = unexpected_failures.keys() - if not len(test_files): - return False - - out_filename = self._fs.join(self._options.results_directory, - "results.html") - with self._fs.open_text_file_for_writing(out_filename) as results_file: - html = self._results_html(test_files, result_summary.failures, results_title) - results_file.write(html) - return True + if not len(test_files): + return - def _show_results_html_file(self): - """Shows the results.html page.""" - results_filename = self._fs.join(self._options.results_directory, - "results.html") + results_filename = self._fs.join(self._results_directory, "results.html") self._port.show_results_html_file(results_filename) diff --git a/Tools/Scripts/webkitpy/layout_tests/layout_package/test_runner2.py b/Tools/Scripts/webkitpy/layout_tests/layout_package/test_runner2.py index 5a6344c..8c19bfe 100644 --- a/Tools/Scripts/webkitpy/layout_tests/layout_package/test_runner2.py +++ b/Tools/Scripts/webkitpy/layout_tests/layout_package/test_runner2.py @@ -117,15 +117,15 @@ class TestRunner2(test_runner.TestRunner): self._group_stats = {} self._worker_states = {} - num_workers = self._num_workers() keyboard_interrupted = False interrupted = False thread_timings = [] self._printer.print_update('Sharding tests ...') test_lists = self._shard_tests(file_list, - num_workers > 1 and not self._options.experimental_fully_parallel) - _log.debug("Using %d shards" % len(test_lists)) + (int(self._options.child_processes) > 1) and not self._options.experimental_fully_parallel) + + num_workers = self._num_workers(len(test_lists)) manager_connection = manager_worker_broker.get(self._port, self._options, self, worker.Worker) diff --git a/Tools/Scripts/webkitpy/layout_tests/layout_package/test_runner_unittest.py b/Tools/Scripts/webkitpy/layout_tests/layout_package/test_runner_unittest.py index 97f8630..82564d2 100644 --- a/Tools/Scripts/webkitpy/layout_tests/layout_package/test_runner_unittest.py +++ b/Tools/Scripts/webkitpy/layout_tests/layout_package/test_runner_unittest.py @@ -44,27 +44,6 @@ class TestRunnerWrapper(test_runner.TestRunner): class TestRunnerTest(unittest.TestCase): - def test_results_html(self): - mock_port = Mock() - mock_port._filesystem = filesystem_mock.MockFileSystem() - mock_port.relative_test_filename = lambda name: name - mock_port.filename_to_uri = lambda name: name - - runner = test_runner.TestRunner(port=mock_port, options=Mock(), - printer=Mock()) - expected_html = u"""<html> - <head> - <title>Layout Test Results (time)</title> - </head> - <body> - <h2>Title (time)</h2> - <p><a href='test_path'>test_path</a><br /> -</p> -</body></html> -""" - html = runner._results_html(["test_path"], {}, "Title", override_time="time") - self.assertEqual(html, expected_html) - def test_shard_tests(self): # Test that _shard_tests in test_runner.TestRunner really # put the http tests first in the queue. diff --git a/Tools/Scripts/webkitpy/layout_tests/layout_package/worker_mixin.py b/Tools/Scripts/webkitpy/layout_tests/layout_package/worker_mixin.py index 7876f91..78d7cdb 100644 --- a/Tools/Scripts/webkitpy/layout_tests/layout_package/worker_mixin.py +++ b/Tools/Scripts/webkitpy/layout_tests/layout_package/worker_mixin.py @@ -55,7 +55,7 @@ class WorkerMixin(object): self._batch_count = 0 self._batch_size = self._options.batch_size self._driver = None - tests_run_filename = self._filesystem.join(self._options.results_directory, + tests_run_filename = self._filesystem.join(port.results_directory(), "tests_run%d.txt" % self._worker_number) self._tests_run_file = self._filesystem.open_text_file_for_writing(tests_run_filename) @@ -159,18 +159,18 @@ class WorkerMixin(object): A TestResult """ worker = self - result = None driver = worker._port.create_driver(worker._worker_number) driver.start() class SingleTestThread(threading.Thread): def run(self): - result = worker._run_single_test(driver, test_input) + self.result = worker._run_single_test(driver, test_input) thread = SingleTestThread() thread.start() thread.join(thread_timeout_sec) + result = getattr(thread, 'result', None) if thread.isAlive(): # If join() returned with the thread still running, the # DumpRenderTree is completely hung and there's nothing diff --git a/Tools/Scripts/webkitpy/layout_tests/port/base.py b/Tools/Scripts/webkitpy/layout_tests/port/base.py index dea126f..c2e565e 100644..100755 --- a/Tools/Scripts/webkitpy/layout_tests/port/base.py +++ b/Tools/Scripts/webkitpy/layout_tests/port/base.py @@ -90,18 +90,24 @@ class Port(object): config=None, **kwargs): self._name = port_name + + # These are default values that should be overridden in a subclasses. + # FIXME: These should really be passed in. + self._operating_system = 'mac' + self._version = '' self._architecture = 'x86' - self._options = options - if self._options is None: - # FIXME: Ideally we'd have a package-wide way to get a - # well-formed options object that had all of the necessary - # options defined on it. - self._options = DummyOptions() + self._graphics_type = 'cpu' + + # FIXME: Ideally we'd have a package-wide way to get a + # well-formed options object that had all of the necessary + # options defined on it. + self._options = options or DummyOptions() + self._executive = executive or Executive() self._user = user or User() self._filesystem = filesystem or system.filesystem.FileSystem() - self._config = config or port_config.Config(self._executive, - self._filesystem) + self._config = config or port_config.Config(self._executive, self._filesystem) + self._helper = None self._http_server = None self._webkit_base_dir = None @@ -123,16 +129,22 @@ class Port(object): # http://bugs.python.org/issue3210 self._wdiff_available = True + # FIXME: prettypatch.py knows this path, why is it copied here? self._pretty_patch_path = self.path_from_webkit_base("Websites", "bugs.webkit.org", "PrettyPatch", "prettify.rb") - # If we're running on a mocked-out filesystem, this file almost - # certainly won't be available, so it's a good test to keep us - # from erroring out later. - self._pretty_patch_available = self._filesystem.exists(self._pretty_patch_path) + self._pretty_patch_available = None + if not hasattr(self._options, 'configuration') or self._options.configuration is None: self._options.configuration = self.default_configuration() self._test_configuration = None self._multiprocessing_is_available = (multiprocessing is not None) + self._results_directory = None + + def wdiff_available(self): + return bool(self._wdiff_available) + + def pretty_patch_available(self): + return bool(self._pretty_patch_available) def default_child_processes(self): """Return the number of DumpRenderTree instances to use for this @@ -171,23 +183,22 @@ class Port(object): """This routine is used to check whether image_diff binary exists.""" raise NotImplementedError('Port.check_image_diff') - def check_pretty_patch(self): + def check_pretty_patch(self, logging=True): """Checks whether we can use the PrettyPatch ruby script.""" - # check if Ruby is installed try: result = self._executive.run_command(['ruby', '--version']) except OSError, e: if e.errno in [errno.ENOENT, errno.EACCES, errno.ECHILD]: - _log.error("Ruby is not installed; " - "can't generate pretty patches.") - _log.error('') + if logging: + _log.error("Ruby is not installed; can't generate pretty patches.") + _log.error('') return False if not self.path_exists(self._pretty_patch_path): - _log.error('Unable to find %s .' % self._pretty_patch_path) - _log.error("Can't generate pretty patches.") - _log.error('') + if logging: + _log.error("Unable to find %s; can't generate pretty patches." % self._pretty_patch_path) + _log.error('') return False return True @@ -200,6 +211,10 @@ class Port(object): interface so that it can be overriden for testing purposes.""" return expected_text != actual_text + def compare_audio(self, expected_audio, actual_audio): + """Return whether the two audio files are *not* equal.""" + return expected_audio != actual_audio + def diff_image(self, expected_contents, actual_contents, diff_filename=None, tolerance=0): """Compare two images and produce a delta image file. @@ -276,7 +291,7 @@ class Port(object): baseline_filename = testname + '-expected' + suffix - baseline_search_path = self.baseline_search_path() + baseline_search_path = self.get_option('additional_platform_directory', []) + self.baseline_search_path() baselines = [] for platform_dir in baseline_search_path: @@ -345,15 +360,22 @@ class Port(object): return None return self._filesystem.read_binary_file(path) + def expected_audio(self, test): + path = self.expected_filename(test, '.wav') + if not self.path_exists(path): + return None + return self._filesystem.read_binary_file(path) + def expected_text(self, test): - """Returns the text output we expect the test to produce. + """Returns the text output we expect the test to produce, or None + if we don't expect there to be any text output. End-of-line characters are normalized to '\n'.""" # FIXME: DRT output is actually utf-8, but since we don't decode the # output from DRT (instead treating it as a binary string), we read the # baselines as a binary string, too. path = self.expected_filename(test, '.txt') if not self.path_exists(path): - return '' + return None text = self._filesystem.read_binary_file(path) return text.replace("\r\n", "\n") @@ -481,16 +503,27 @@ class Port(object): self._filesystem.maybe_make_directory(*path) def name(self): - """Return the name of the port (e.g., 'mac', 'chromium-win-xp'). - - Note that this is different from the test_platform_name(), which - may be different (e.g., 'win-xp' instead of 'chromium-win-xp'.""" + """Return the name of the port (e.g., 'mac', 'chromium-win-xp').""" return self._name + def operating_system(self): + return self._operating_system + + def version(self): + """Returns a string indicating the version of a given platform, e.g. + 'leopard' or 'xp'. + + This is used to help identify the exact port when parsing test + expectations, determining search paths, and logging information.""" + return self._version + def graphics_type(self): """Returns whether the port uses accelerated graphics ('gpu') or not ('cpu').""" - return 'cpu' + return self._graphics_type + + def architecture(self): + return self._architecture def real_name(self): """Returns the actual name of the port, not the delegate's.""" @@ -541,8 +574,15 @@ class Port(object): return self._filesystem.normpath(self._filesystem.join(self.layout_tests_dir(), test_name)) def results_directory(self): - """Absolute path to the place to store the test results.""" - raise NotImplementedError('Port.results_directory') + """Absolute path to the place to store the test results (uses --results-directory).""" + if not self._results_directory: + option_val = self.get_option('results_directory') or self.default_results_directory() + self._results_directory = self._filesystem.abspath(option_val) + return self._results_directory + + def default_results_directory(self): + """Absolute path to the default place to store the test results.""" + raise NotImplementedError() def setup_test_run(self): """Perform port-specific work at the beginning of a test run.""" @@ -578,18 +618,16 @@ class Port(object): is already running.""" if self.get_option('use_apache'): self._http_server = apache_http_server.LayoutTestApacheHttpd(self, - self.get_option('results_directory')) + self.results_directory()) else: - self._http_server = http_server.Lighttpd(self, - self.get_option('results_directory')) + self._http_server = http_server.Lighttpd(self, self.results_directory()) self._http_server.start() def start_websocket_server(self): """Start a websocket server if it is available. Do nothing if it isn't. This routine is allowed to (and may) fail if a server is already running.""" - self._websocket_server = websocket_server.PyWebSocket(self, - self.get_option('results_directory')) + self._websocket_server = websocket_server.PyWebSocket(self, self.results_directory()) self._websocket_server.start() def acquire_http_lock(self): @@ -631,6 +669,14 @@ class Port(object): def all_test_configurations(self): return self.test_configuration().all_test_configurations() + def all_baseline_variants(self): + """Returns a list of platform names sufficient to cover all the baselines. + + The list should be sorted so that a later platform will reuse + an earlier platform's baselines if they are the same (e.g., + 'snowleopard' should precede 'leopard').""" + raise NotImplementedError + def test_expectations(self): """Returns the test expectations for this port. @@ -647,39 +693,6 @@ class Port(object): sync up the two repos.""" return None - def test_platform_name(self): - """Returns the string that corresponds to the given platform name - in the test expectations. This may be the same as name(), or it - may be different. For example, chromium returns 'mac' for - 'chromium-mac'.""" - raise NotImplementedError('Port.test_platform_name') - - def test_platforms(self): - """Returns the list of test platform identifiers as used in the - test_expectations and on dashboards, the rebaselining tool, etc. - - Note that this is not necessarily the same as the list of ports, - which must be globally unique (e.g., both 'chromium-mac' and 'mac' - might return 'mac' as a test_platform name'.""" - raise NotImplementedError('Port.platforms') - - def test_platform_name_to_name(self, test_platform_name): - """Returns the Port platform name that corresponds to the name as - referenced in the expectations file. E.g., "mac" returns - "chromium-mac" on the Chromium ports.""" - raise NotImplementedError('Port.test_platform_name_to_name') - - def architecture(self): - return self._architecture - - def version(self): - """Returns a string indicating the version of a given platform, e.g. - 'leopard' or 'xp'. - - This is used to help identify the exact port when parsing test - expectations, determining search paths, and logging information.""" - raise NotImplementedError('Port.version') - def test_repository_paths(self): """Returns a list of (repository_name, repository_path) tuples of its depending code base. By default it returns a list that only @@ -748,6 +761,8 @@ class Port(object): _pretty_patch_error_html = "Failed to run PrettyPatch, see error log." def pretty_patch_text(self, diff_path): + if self._pretty_patch_available is None: + self._pretty_patch_available = self.check_pretty_patch(logging=False) if not self._pretty_patch_available: return self._pretty_patch_error_html command = ("ruby", "-I", self._filesystem.dirname(self._pretty_patch_path), @@ -875,22 +890,24 @@ class DriverInput(object): class DriverOutput(object): """Groups information about a output from driver for easy passing of data.""" - def __init__(self, text, image, image_hash, - crash=False, test_time=None, timeout=False, error=''): + def __init__(self, text, image, image_hash, audio, + crash=False, test_time=0, timeout=False, error=''): """Initializes a TestOutput object. Args: text: a text output image: an image output image_hash: a string containing the checksum of the image + audio: contents of an audio stream, if any (in WAV format) crash: a boolean indicating whether the driver crashed on the test - test_time: a time which the test has taken + test_time: the time the test took to execute timeout: a boolean indicating whehter the test timed out error: any unexpected or additional (or error) text output """ self.text = text self.image = image self.image_hash = image_hash + self.audio = audio self.crash = crash self.test_time = test_time self.timeout = timeout @@ -956,15 +973,8 @@ class Driver: class TestConfiguration(object): def __init__(self, port=None, os=None, version=None, architecture=None, build_type=None, graphics_type=None): - - # FIXME: We can get the O/S and version from test_platform_name() - # and version() for now, but those should go away and be cleaned up - # with more generic methods like operation_system() and os_version() - # or something. - if port: - port_version = port.version() - self.os = os or port.test_platform_name().replace('-' + port_version, '') - self.version = version or port_version + self.os = os or port.operating_system() + self.version = version or port.version() self.architecture = architecture or port.architecture() self.build_type = build_type or port._options.configuration.lower() self.graphics_type = graphics_type or port.graphics_type() diff --git a/Tools/Scripts/webkitpy/layout_tests/port/base_unittest.py b/Tools/Scripts/webkitpy/layout_tests/port/base_unittest.py index ef90484..b4758fc 100644 --- a/Tools/Scripts/webkitpy/layout_tests/port/base_unittest.py +++ b/Tools/Scripts/webkitpy/layout_tests/port/base_unittest.py @@ -33,7 +33,7 @@ import unittest from webkitpy.common.system.executive import Executive, ScriptError from webkitpy.common.system import executive_mock -from webkitpy.common.system import filesystem +from webkitpy.common.system.filesystem_mock import MockFileSystem from webkitpy.common.system import outputcapture from webkitpy.common.system.path import abspath_to_uri from webkitpy.thirdparty.mock import Mock @@ -86,8 +86,8 @@ class PortTest(unittest.TestCase): def test_pretty_patch_script_error(self): # FIXME: This is some ugly white-box test hacking ... - base._pretty_patch_available = True port = base.Port(executive=executive_mock.MockExecutive2(exception=ScriptError)) + port._pretty_patch_available = True self.assertEqual(port.pretty_patch_text("patch.txt"), port._pretty_patch_error_html) @@ -232,6 +232,33 @@ class PortTest(unittest.TestCase): port = base.Port(port_name='foo') self.assertEqual(port.name(), 'foo') + def test_additional_platform_directory(self): + filesystem = MockFileSystem() + options, args = optparse.OptionParser().parse_args([]) + port = base.Port(port_name='foo', filesystem=filesystem, options=options) + port.baseline_search_path = lambda: [] + layout_test_dir = port.layout_tests_dir() + test_file = filesystem.join(layout_test_dir, 'fast', 'test.html') + + # No additional platform directory + self.assertEqual( + port.expected_baselines(test_file, '.txt'), + [(None, 'fast/test-expected.txt')]) + + # Simple additional platform directory + options.additional_platform_directory = ['/tmp/local-baselines'] + filesystem.files = { + '/tmp/local-baselines/fast/test-expected.txt': 'foo', + } + self.assertEqual( + port.expected_baselines(test_file, '.txt'), + [('/tmp/local-baselines', 'fast/test-expected.txt')]) + + # Multiple additional platform directories + options.additional_platform_directory = ['/foo', '/tmp/local-baselines'] + self.assertEqual( + port.expected_baselines(test_file, '.txt'), + [('/tmp/local-baselines', 'fast/test-expected.txt')]) class VirtualTest(unittest.TestCase): """Tests that various methods expected to be virtual are.""" @@ -247,13 +274,8 @@ class VirtualTest(unittest.TestCase): self.assertVirtual(port.create_driver, 0) self.assertVirtual(port.diff_image, None, None) self.assertVirtual(port.path_to_test_expectations_file) - self.assertVirtual(port.test_platform_name) - self.assertVirtual(port.results_directory) + self.assertVirtual(port.default_results_directory) self.assertVirtual(port.test_expectations) - self.assertVirtual(port.test_platform_name) - self.assertVirtual(port.test_platforms) - self.assertVirtual(port.test_platform_name_to_name, None) - self.assertVirtual(port.version) self.assertVirtual(port._path_to_apache) self.assertVirtual(port._path_to_apache_config_file) self.assertVirtual(port._path_to_driver) diff --git a/Tools/Scripts/webkitpy/layout_tests/port/chromium.py b/Tools/Scripts/webkitpy/layout_tests/port/chromium.py index baf1893..a4279b4 100644 --- a/Tools/Scripts/webkitpy/layout_tests/port/chromium.py +++ b/Tools/Scripts/webkitpy/layout_tests/port/chromium.py @@ -51,6 +51,12 @@ _log = logging.getLogger("webkitpy.layout_tests.port.chromium") # FIXME: This function doesn't belong in this package. class ChromiumPort(base.Port): """Abstract base class for Chromium implementations of the Port class.""" + ALL_BASELINE_VARIANTS = [ + 'chromium-mac-snowleopard', 'chromium-mac-leopard', + 'chromium-win-win7', 'chromium-win-vista', 'chromium-win-xp', + 'chromium-linux-x86', 'chromium-linux-x86_64', + 'chromium-gpu-mac-snowleopard', 'chromium-gpu-win-win7', 'chromium-gpu-linux-x86_64', + ] def __init__(self, **kwargs): base.Port.__init__(self, **kwargs) @@ -102,7 +108,7 @@ class ChromiumPort(base.Port): # It's okay if pretty patch isn't available, but we will at # least log a message. - self.check_pretty_patch() + self._pretty_patch_available = self.check_pretty_patch() return result @@ -130,7 +136,11 @@ class ChromiumPort(base.Port): def diff_image(self, expected_contents, actual_contents, diff_filename=None): - executable = self._path_to_image_diff() + # FIXME: need unit tests for this. + if not actual_contents and not expected_contents: + return False + if not actual_contents or not expected_contents: + return True tempdir = self._filesystem.mkdtemp() expected_filename = self._filesystem.join(str(tempdir), "expected.png") @@ -138,6 +148,7 @@ class ChromiumPort(base.Port): actual_filename = self._filesystem.join(str(tempdir), "actual.png") self._filesystem.write_binary_file(actual_filename, actual_contents) + executable = self._path_to_image_diff() if diff_filename: cmd = [executable, '--diff', expected_filename, actual_filename, diff_filename] @@ -189,14 +200,14 @@ class ChromiumPort(base.Port): return self.path_from_webkit_base('LayoutTests', 'platform', 'chromium', 'test_expectations.txt') - def results_directory(self): + def default_results_directory(self): try: return self.path_from_chromium_base('webkit', self.get_option('configuration'), - self.get_option('results_directory')) + 'layout-test-results') except AssertionError: return self._build_path(self.get_option('configuration'), - self.get_option('results_directory')) + 'layout-test-results') def setup_test_run(self): # Delete the disk cache if any to ensure a clean test run. @@ -230,6 +241,9 @@ class ChromiumPort(base.Port): # http://bugs.python.org/issue1731717 self._helper.wait() + def all_baseline_variants(self): + return self.ALL_BASELINE_VARIANTS + def test_expectations(self): """Returns the test expectations for this port. @@ -251,7 +265,6 @@ class ChromiumPort(base.Port): def skipped_layout_tests(self, extra_test_files=None): expectations_str = self.test_expectations() overrides_str = self.test_expectations_overrides() - test_platform_name = self.test_platform_name() is_debug_mode = False all_test_files = self.tests([]) @@ -265,15 +278,6 @@ class ChromiumPort(base.Port): return [self.relative_test_filename(test) for test in expectations.get_tests_with_result_type(test_expectations.SKIP)] - def test_platform_names(self): - return ('mac', 'win', 'linux', 'win-xp', 'win-vista', 'win-7') - - def test_platform_name_to_name(self, test_platform_name): - if test_platform_name in self.test_platform_names(): - return 'chromium-' + test_platform_name - raise ValueError('Unsupported test_platform_name: %s' % - test_platform_name) - def test_repository_paths(self): # Note: for JSON file's backward-compatibility we use 'chrome' rather # than 'chromium' here. @@ -335,9 +339,9 @@ class ChromiumDriver(base.Driver): self._port = port self._worker_number = worker_number self._image_path = None + self.KILL_TIMEOUT = 3.0 if self._port.get_option('pixel_tests'): - self._image_path = self._port._filesystem.join( - self._port.get_option('results_directory'), + self._image_path = self._port._filesystem.join(self._port.results_directory(), 'png_result%s.png' % self._worker_number) def cmd_line(self): @@ -371,6 +375,8 @@ class ChromiumDriver(base.Driver): cmd.append('--enable-accelerated-2d-canvas') if self._port.get_option('enable_hardware_gpu'): cmd.append('--enable-hardware-gpu') + + cmd.extend(self._port.get_option('additional_drt_flag', [])) return cmd def start(self): @@ -426,7 +432,7 @@ class ChromiumDriver(base.Driver): if png_path and self._port._filesystem.exists(png_path): return self._port._filesystem.read_binary_file(png_path) else: - return '' + return None def _output_image_with_retry(self): # Retry a few more times because open() sometimes fails on Windows, @@ -501,11 +507,16 @@ class ChromiumDriver(base.Driver): (line, crash) = self._write_command_and_read_line(input=None) + # FIXME: Add support for audio when we're ready. + run_time = time.time() - start_time output_image = self._output_image_with_retry() - assert output_image is not None - return base.DriverOutput(''.join(output), output_image, actual_checksum, - crash, run_time, timeout, ''.join(error)) + text = ''.join(output) + if not text: + text = None + + return base.DriverOutput(text, output_image, actual_checksum, audio=None, + crash=crash, test_time=run_time, timeout=timeout, error=''.join(error)) def stop(self): if self._proc: @@ -513,21 +524,19 @@ class ChromiumDriver(base.Driver): self._proc.stdout.close() if self._proc.stderr: self._proc.stderr.close() - if sys.platform not in ('win32', 'cygwin'): - # Closing stdin/stdout/stderr hangs sometimes on OS X, - # (see __init__(), above), and anyway we don't want to hang - # the harness if DRT is buggy, so we wait a couple - # seconds to give DRT a chance to clean up, but then - # force-kill the process if necessary. - KILL_TIMEOUT = 3.0 - timeout = time.time() + KILL_TIMEOUT - # poll() is not threadsafe and can throw OSError due to: - # http://bugs.python.org/issue1731717 - while self._proc.poll() is None and time.time() < timeout: - time.sleep(0.1) - # poll() is not threadsafe and can throw OSError due to: - # http://bugs.python.org/issue1731717 - if self._proc.poll() is None: - _log.warning('stopping test driver timed out, ' - 'killing it') - self._port._executive.kill_process(self._proc.pid) + # Closing stdin/stdout/stderr hangs sometimes on OS X, + # (see __init__(), above), and anyway we don't want to hang + # the harness if DRT is buggy, so we wait a couple + # seconds to give DRT a chance to clean up, but then + # force-kill the process if necessary. + timeout = time.time() + self.KILL_TIMEOUT + while self._proc.poll() is None and time.time() < timeout: + time.sleep(0.1) + if self._proc.poll() is None: + _log.warning('stopping test driver timed out, ' + 'killing it') + self._port._executive.kill_process(self._proc.pid) + # FIXME: This is sometime none. What is wrong? assert self._proc.poll() is not None + if self._proc.poll() is not None: + self._proc.wait() + self._proc = None diff --git a/Tools/Scripts/webkitpy/layout_tests/port/chromium_gpu.py b/Tools/Scripts/webkitpy/layout_tests/port/chromium_gpu.py index 167f23e..ffc2cf7 100644 --- a/Tools/Scripts/webkitpy/layout_tests/port/chromium_gpu.py +++ b/Tools/Scripts/webkitpy/layout_tests/port/chromium_gpu.py @@ -60,6 +60,7 @@ def get(platform=None, port_name='chromium-gpu', **kwargs): # FIXME: These should really be a mixin class. def _set_gpu_options(port): + port._graphics_type = 'gpu' if port.get_option('accelerated_compositing') is None: port._options.accelerated_compositing = True if port.get_option('accelerated_2d_canvas') is None: @@ -84,17 +85,6 @@ def _tests(port, paths): return test_files.find(port, paths) -def _test_platform_names(self): - return ('mac', 'win', 'linux') - - -def _test_platform_name_to_name(self, test_platform_name): - if test_platform_name in self.test_platform_names(): - return 'chromium-gpu-' + test_platform_name - raise ValueError('Unsupported test_platform_name: %s' % - test_platform_name) - - class ChromiumGpuLinuxPort(chromium_linux.ChromiumLinuxPort): def __init__(self, port_name='chromium-gpu-linux', **kwargs): chromium_linux.ChromiumLinuxPort.__init__(self, port_name=port_name, **kwargs) @@ -112,21 +102,9 @@ class ChromiumGpuLinuxPort(chromium_linux.ChromiumLinuxPort): def default_child_processes(self): return 1 - def graphics_type(self): - return 'gpu' - def tests(self, paths): return _tests(self, paths) - def test_platform_name(self): - return 'linux' - - def test_platform_names(self): - return _test_platform_names(self) - - def test_platform_name_to_name(self, name): - return _test_platform_name_to_name(self, name) - class ChromiumGpuMacPort(chromium_mac.ChromiumMacPort): def __init__(self, port_name='chromium-gpu-mac', **kwargs): @@ -144,21 +122,9 @@ class ChromiumGpuMacPort(chromium_mac.ChromiumMacPort): def default_child_processes(self): return 1 - def graphics_type(self): - return 'gpu' - def tests(self, paths): return _tests(self, paths) - def test_platform_name(self): - return 'mac' - - def test_platform_names(self): - return _test_platform_names(self) - - def test_platform_name_to_name(self, name): - return _test_platform_name_to_name(self, name) - class ChromiumGpuWinPort(chromium_win.ChromiumWinPort): def __init__(self, port_name='chromium-gpu-win', **kwargs): @@ -176,17 +142,5 @@ class ChromiumGpuWinPort(chromium_win.ChromiumWinPort): def default_child_processes(self): return 1 - def graphics_type(self): - return 'gpu' - def tests(self, paths): return _tests(self, paths) - - def test_platform_name(self): - return 'win' - - def test_platform_names(self): - return _test_platform_names(self) - - def test_platform_name_to_name(self, name): - return _test_platform_name_to_name(self, name) diff --git a/Tools/Scripts/webkitpy/layout_tests/port/chromium_linux.py b/Tools/Scripts/webkitpy/layout_tests/port/chromium_linux.py index 2cd2435..49c01c4 100644 --- a/Tools/Scripts/webkitpy/layout_tests/port/chromium_linux.py +++ b/Tools/Scripts/webkitpy/layout_tests/port/chromium_linux.py @@ -47,27 +47,29 @@ class ChromiumLinuxPort(chromium.ChromiumPort): 'x86': ['chromium-linux', 'chromium-win', 'chromium', 'win', 'mac'], } - def __init__(self, port_name=None, rebaselining=False, **kwargs): + def __init__(self, port_name=None, **kwargs): port_name = port_name or 'chromium-linux' chromium.ChromiumPort.__init__(self, port_name=port_name, **kwargs) # We re-set the port name once the base object is fully initialized # in order to be able to find the DRT binary properly. - if port_name.endswith('-linux') and not rebaselining: + if port_name.endswith('-linux'): self._architecture = self._determine_architecture() # FIXME: this is an ugly hack to avoid renaming the GPU port. if port_name == 'chromium-linux': port_name = port_name + '-' + self._architecture - elif rebaselining: - self._architecture = 'x86' else: base, arch = port_name.rsplit('-', 1) assert base in ('chromium-linux', 'chromium-gpu-linux') self._architecture = arch assert self._architecture in self.SUPPORTED_ARCHITECTURES assert port_name in ('chromium-linux', 'chromium-gpu-linux', - 'chromium-linux-x86', 'chromium-linux-x86_64') + 'chromium-linux-x86', 'chromium-linux-x86_64', + 'chromium-gpu-linux-x86_64') self._name = port_name + self._operating_system = 'linux' + # FIXME: add support for 'lucid' + self._version = 'hardy' def _determine_architecture(self): driver_path = self._path_to_driver() @@ -114,14 +116,6 @@ class ChromiumLinuxPort(chromium.ChromiumPort): 'LinuxBuildInstructions') return result - def test_platform_name(self): - # We use 'linux' instead of 'chromium-linux' in test_expectations.txt. - return 'linux' - - def version(self): - # FIXME: add support for Lucid. - return 'hardy' - # # PROTECTED METHODS # diff --git a/Tools/Scripts/webkitpy/layout_tests/port/chromium_mac.py b/Tools/Scripts/webkitpy/layout_tests/port/chromium_mac.py index 141b587..7f57bdf 100644 --- a/Tools/Scripts/webkitpy/layout_tests/port/chromium_mac.py +++ b/Tools/Scripts/webkitpy/layout_tests/port/chromium_mac.py @@ -43,7 +43,7 @@ _log = logging.getLogger("webkitpy.layout_tests.port.chromium_mac") class ChromiumMacPort(chromium.ChromiumPort): """Chromium Mac implementation of the Port class.""" - SUPPORTED_OS_VERSIONS = ('leopard', 'snowleopard') + SUPPORTED_OS_VERSIONS = ('leopard', 'snowleopard', 'future') FALLBACK_PATHS = { 'leopard': [ @@ -60,41 +60,28 @@ class ChromiumMacPort(chromium.ChromiumPort): 'mac-snowleopard', 'mac', ], - '': [ + 'future': [ 'chromium-mac', 'chromium', 'mac', ], } - def __init__(self, port_name=None, os_version_string=None, rebaselining=False, **kwargs): + def __init__(self, port_name=None, os_version_string=None, **kwargs): # We're a little generic here because this code is reused by the # 'google-chrome' port as well as the 'mock-' and 'dryrun-' ports. port_name = port_name or 'chromium-mac' - + chromium.ChromiumPort.__init__(self, port_name=port_name, **kwargs) if port_name.endswith('-mac'): - # FIXME: The rebaselining flag is an ugly hack that lets us create an - # "chromium-mac" port that is not version-specific. It should only be - # used by rebaseline-chromium-webkit-tests to explicitly put files into - # the generic directory. In theory we shouldn't need this, because - # the newest mac port should be using 'chromium-mac' as the baseline - # directory. However, we also don't have stable SL bots :( - # - # When we remove this FIXME, we also need to remove '' as a valid - # fallback key in self.FALLBACK_PATHS. - if rebaselining: - self._version = '' - else: - self._version = mac.os_version(os_version_string, self.SUPPORTED_OS_VERSIONS) - port_name = port_name + '-' + self._version + self._version = mac.os_version(os_version_string, self.SUPPORTED_OS_VERSIONS) + self._name = port_name + '-' + self._version else: self._version = port_name[port_name.index('-mac-') + 5:] assert self._version in self.SUPPORTED_OS_VERSIONS - - chromium.ChromiumPort.__init__(self, port_name=port_name, **kwargs) + self._operating_system = 'mac' def baseline_path(self): - if self.version() == 'snowleopard': + if self.version() in ('snowleopard', 'future'): # We treat Snow Leopard as the newest version of mac, # so it gets the base dir. return self._webkit_baseline_path('chromium-mac') @@ -123,15 +110,6 @@ class ChromiumMacPort(chromium.ChromiumPort): def driver_name(self): return "DumpRenderTree" - def test_platform_name(self): - # We use 'mac' instead of 'chromium-mac' - - # FIXME: Get rid of this method after rebaseline_chromium_webkit_tests dies. - return 'mac' - - def version(self): - return self._version - # # PROTECTED METHODS # diff --git a/Tools/Scripts/webkitpy/layout_tests/port/chromium_mac_unittest.py b/Tools/Scripts/webkitpy/layout_tests/port/chromium_mac_unittest.py index 12011c6..4f9c302 100644 --- a/Tools/Scripts/webkitpy/layout_tests/port/chromium_mac_unittest.py +++ b/Tools/Scripts/webkitpy/layout_tests/port/chromium_mac_unittest.py @@ -53,7 +53,7 @@ class ChromiumMacPortTest(port_testcase.PortTestCase): def test_versions(self): port = chromium_mac.ChromiumMacPort() - self.assertTrue(port.name() in ('chromium-mac-leopard', 'chromium-mac-snowleopard')) + self.assertTrue(port.name() in ('chromium-mac-leopard', 'chromium-mac-snowleopard', 'chromium-mac-future')) self.assert_name(None, '10.5.3', 'chromium-mac-leopard') self.assert_name('chromium-mac', '10.5.3', 'chromium-mac-leopard') @@ -65,18 +65,16 @@ class ChromiumMacPortTest(port_testcase.PortTestCase): self.assert_name('chromium-mac-snowleopard', '10.5.3', 'chromium-mac-snowleopard') self.assert_name('chromium-mac-snowleopard', '10.6.3', 'chromium-mac-snowleopard') - self.assertRaises(KeyError, self.assert_name, None, '10.7.1', 'chromium-mac-leopard') - self.assertRaises(AssertionError, self.assert_name, None, '10.4.1', 'chromium-mac-leopard') + self.assert_name(None, '10.7', 'chromium-mac-future') + self.assert_name(None, '10.7.3', 'chromium-mac-future') + self.assert_name(None, '10.8', 'chromium-mac-future') + self.assert_name('chromium-mac', '10.7.3', 'chromium-mac-future') + self.assert_name('chromium-mac-future', '10.4.3', 'chromium-mac-future') + self.assert_name('chromium-mac-future', '10.5.3', 'chromium-mac-future') + self.assert_name('chromium-mac-future', '10.6.3', 'chromium-mac-future') + self.assert_name('chromium-mac-future', '10.7.3', 'chromium-mac-future') - def test_generic_rebaselining_port(self): - port = chromium_mac.ChromiumMacPort(rebaselining=True) - self.assertEquals(port.name(), 'chromium-mac') - self.assertEquals(port.version(), '') - self.assertEquals(port.baseline_path(), port._webkit_baseline_path(port.name())) - - port = chromium_mac.ChromiumMacPort(port_name='chromium-mac-leopard', rebaselining=True) - self.assertEquals(port.name(), 'chromium-mac-leopard') - self.assertEquals(port.baseline_path(), port._webkit_baseline_path(port.name())) + self.assertRaises(AssertionError, self.assert_name, None, '10.4.1', 'should-raise-assertion-so-this-value-does-not-matter') def test_baseline_path(self): port = chromium_mac.ChromiumMacPort(port_name='chromium-mac-leopard') diff --git a/Tools/Scripts/webkitpy/layout_tests/port/chromium_unittest.py b/Tools/Scripts/webkitpy/layout_tests/port/chromium_unittest.py index b287875..0260dff 100644 --- a/Tools/Scripts/webkitpy/layout_tests/port/chromium_unittest.py +++ b/Tools/Scripts/webkitpy/layout_tests/port/chromium_unittest.py @@ -41,8 +41,10 @@ import chromium_linux import chromium_mac import chromium_win -class ChromiumDriverTest(unittest.TestCase): +from webkitpy.layout_tests.port import port_testcase + +class ChromiumDriverTest(unittest.TestCase): def setUp(self): mock_port = Mock() mock_port.get_option = lambda option_name: '' @@ -85,8 +87,46 @@ class ChromiumDriverTest(unittest.TestCase): self.driver._proc.stdout.readline = mock_readline self._assert_write_command_and_read_line(expected_crash=True) + def test_stop(self): + self.pid = None + self.wait_called = False + self.driver._proc = Mock() + self.driver._proc.pid = 1 + self.driver._proc.stdin = StringIO.StringIO() + self.driver._proc.stdout = StringIO.StringIO() + self.driver._proc.stderr = StringIO.StringIO() + self.driver._proc.poll = lambda: None + + def fake_wait(): + self.assertTrue(self.pid is not None) + self.wait_called = True + + self.driver._proc.wait = fake_wait + + class FakeExecutive(object): + def kill_process(other, pid): + self.pid = pid + self.driver._proc.poll = lambda: 2 + + self.driver._port._executive = FakeExecutive() + self.driver.KILL_TIMEOUT = 0.01 + self.driver.stop() + self.assertTrue(self.wait_called) + self.assertEquals(self.pid, 1) + + +class ChromiumPortTest(port_testcase.PortTestCase): + def port_maker(self, platform): + return chromium.ChromiumPort + + def test_driver_cmd_line(self): + # Override this test since ChromiumPort doesn't implement driver_cmd_line(). + pass + + def test_baseline_search_path(self): + # Override this test since ChromiumPort doesn't implement baseline_search_path(). + pass -class ChromiumPortTest(unittest.TestCase): class TestMacPort(chromium_mac.ChromiumMacPort): def __init__(self, options): chromium_mac.ChromiumMacPort.__init__(self, diff --git a/Tools/Scripts/webkitpy/layout_tests/port/chromium_win.py b/Tools/Scripts/webkitpy/layout_tests/port/chromium_win.py index d0908df..171519e 100644 --- a/Tools/Scripts/webkitpy/layout_tests/port/chromium_win.py +++ b/Tools/Scripts/webkitpy/layout_tests/port/chromium_win.py @@ -63,34 +63,21 @@ class ChromiumWinPort(chromium.ChromiumPort): 'xp': ['chromium-win-xp', 'chromium-win-vista', 'chromium-win', 'chromium', 'win', 'mac'], 'vista': ['chromium-win-vista', 'chromium-win', 'chromium', 'win', 'mac'], 'win7': ['chromium-win', 'chromium', 'win', 'mac'], - '': ['chromium-win', 'chromium', 'win', 'mac'], } - def __init__(self, port_name=None, windows_version=None, rebaselining=False, **kwargs): + def __init__(self, port_name=None, windows_version=None, **kwargs): # We're a little generic here because this code is reused by the # 'google-chrome' port as well as the 'mock-' and 'dryrun-' ports. port_name = port_name or 'chromium-win' - + chromium.ChromiumPort.__init__(self, port_name=port_name, **kwargs) if port_name.endswith('-win'): - # FIXME: The rebaselining flag is an ugly hack that lets us create an - # "chromium-win" port that is not version-specific. It should only be - # used by rebaseline-chromium-webkit-tests to explicitly put files into - # the generic directory. In theory we shouldn't need this, because - # the newest win port should be using 'chromium-win' as the baseline - # directory. However, we also don't have stable Win 7 bots :( - # - # When we remove this FIXME, we also need to remove '' as a valid - # fallback key in self.FALLBACK_PATHS. - if rebaselining: - self._version = '' - else: - self._version = os_version(windows_version) - port_name = port_name + '-' + self._version + self._version = os_version(windows_version) + self._name = port_name + '-' + self._version else: self._version = port_name[port_name.index('-win-') + 5:] assert self._version in self.SUPPORTED_VERSIONS - chromium.ChromiumPort.__init__(self, port_name=port_name, **kwargs) + self._operating_system = 'win' def setup_environ_for_server(self): env = chromium.ChromiumPort.setup_environ_for_server(self) @@ -129,25 +116,10 @@ class ChromiumWinPort(chromium.ChromiumPort): 'build-instructions-windows') return result - def default_worker_model(self): - # FIXME: should use base class method instead. See bug 55163. - return 'old-threads' - def relative_test_filename(self, filename): path = filename[len(self.layout_tests_dir()) + 1:] return path.replace('\\', '/') - def test_platform_name(self): - # We return 'win-xp', not 'chromium-win-xp' here, for convenience. - - # FIXME: Get rid of this method after rebaseline_chromium_webkit_tests dies. - if self.version() == '': - return 'win' - return 'win-' + self.version() - - def version(self): - return self._version - # # PROTECTED ROUTINES # diff --git a/Tools/Scripts/webkitpy/layout_tests/port/chromium_win_unittest.py b/Tools/Scripts/webkitpy/layout_tests/port/chromium_win_unittest.py index 8ea7060..9fb9e2d 100644 --- a/Tools/Scripts/webkitpy/layout_tests/port/chromium_win_unittest.py +++ b/Tools/Scripts/webkitpy/layout_tests/port/chromium_win_unittest.py @@ -58,13 +58,6 @@ class ChromiumWinTest(port_testcase.PortTestCase): def _mock_path_from_chromium_base(self, *comps): return self._port._filesystem.join("/chromium/src", *comps) - def test_default_worker_model(self): - port = self.make_port() - if not port: - return - - self.assertEqual(port.default_worker_model(), 'old-threads') - def test_setup_environ_for_server(self): port = self.make_port() if not port: @@ -127,16 +120,6 @@ class ChromiumWinTest(port_testcase.PortTestCase): self.assertRaises(KeyError, self.assert_name, None, (5, 2), 'chromium-win-xp') self.assertRaises(KeyError, self.assert_name, None, (7, 1), 'chromium-win-xp') - def test_generic_rebaselining_port(self): - port = chromium_win.ChromiumWinPort(rebaselining=True) - self.assertEquals(port.name(), 'chromium-win') - self.assertEquals(port.version(), '') - self.assertEquals(port.baseline_path(), port._webkit_baseline_path(port.name())) - - port = chromium_win.ChromiumWinPort(port_name='chromium-win-xp', rebaselining=True) - self.assertEquals(port.name(), 'chromium-win-xp') - self.assertEquals(port.baseline_path(), port._webkit_baseline_path(port.name())) - def test_baseline_path(self): port = chromium_win.ChromiumWinPort(port_name='chromium-win-xp') self.assertEquals(port.baseline_path(), port._webkit_baseline_path('chromium-win-xp')) diff --git a/Tools/Scripts/webkitpy/layout_tests/port/dryrun.py b/Tools/Scripts/webkitpy/layout_tests/port/dryrun.py index 20aa776..ba99636 100644 --- a/Tools/Scripts/webkitpy/layout_tests/port/dryrun.py +++ b/Tools/Scripts/webkitpy/layout_tests/port/dryrun.py @@ -119,29 +119,25 @@ class DryrunDriver(base.Driver): def run_test(self, driver_input): start_time = time.time() fs = self._port._filesystem - if fs.exists(self._port.reftest_expected_filename(driver_input.filename)) or \ - fs.exists(self._port.reftest_expected_mismatch_filename(driver_input.filename)): - text_output = 'test-text' + if (fs.exists(self._port.reftest_expected_filename(driver_input.filename)) or + fs.exists(self._port.reftest_expected_mismatch_filename(driver_input.filename)) or + driver_input.filename.endswith('-expected.html')): + text = 'test-text' image = 'test-image' - hash = 'test-checksum' - elif driver_input.filename.endswith('-expected.html'): - text_output = 'test-text' - image = 'test-image' - hash = 'test-checksum' + checksum = 'test-checksum' + audio = None elif driver_input.filename.endswith('-expected-mismatch.html'): - text_output = 'test-text-mismatch' + text = 'test-text-mismatch' image = 'test-image-mismatch' - hash = 'test-checksum-mismatch' - elif driver_input.image_hash is not None: - text_output = self._port.expected_text(driver_input.filename) - image = self._port.expected_image(driver_input.filename) - hash = self._port.expected_checksum(driver_input.filename) + checksum = 'test-checksum-mismatch' + audio = None else: - text_output = self._port.expected_text(driver_input.filename) - image = None - hash = None - return base.DriverOutput(text_output, image, hash, False, - time.time() - start_time, False, '') + text = self._port.expected_text(driver_input.filename) + image = self._port.expected_image(driver_input.filename) + checksum = self._port.expected_checksum(driver_input.filename) + audio = self._port.expected_audio(driver_input.filename) + return base.DriverOutput(text, image, checksum, audio, crash=False, + test_time=time.time() - start_time, timeout=False, error='') def start(self): pass diff --git a/Tools/Scripts/webkitpy/layout_tests/port/http_server.py b/Tools/Scripts/webkitpy/layout_tests/port/http_server.py index 1753aee..5ba767f 100755 --- a/Tools/Scripts/webkitpy/layout_tests/port/http_server.py +++ b/Tools/Scripts/webkitpy/layout_tests/port/http_server.py @@ -214,7 +214,7 @@ class Lighttpd(http_server_base.HttpServerBase): env = self._port_obj.setup_environ_for_server() _log.debug('Starting http server, cmd="%s"' % str(start_cmd)) # FIXME: Should use Executive.run_command - self._process = subprocess.Popen(start_cmd, env=env) + self._process = subprocess.Popen(start_cmd, env=env, stdin=subprocess.PIPE) # Wait for server to start. self.mappings = mappings diff --git a/Tools/Scripts/webkitpy/layout_tests/port/mac.py b/Tools/Scripts/webkitpy/layout_tests/port/mac.py index 4315543..a44d6d3 100644 --- a/Tools/Scripts/webkitpy/layout_tests/port/mac.py +++ b/Tools/Scripts/webkitpy/layout_tests/port/mac.py @@ -39,7 +39,6 @@ _log = logging.getLogger("webkitpy.layout_tests.port.mac") def os_version(os_version_string=None, supported_versions=None): - # We only support Tiger, Leopard, and Snow Leopard. if not os_version_string: if hasattr(platform, 'mac_ver') and platform.mac_ver()[0]: os_version_string = platform.mac_ver()[0] @@ -52,7 +51,8 @@ def os_version(os_version_string=None, supported_versions=None): 5: 'leopard', 6: 'snowleopard', } - version_string = version_strings[release_version] + assert release_version >= min(version_strings.keys()) + version_string = version_strings.get(release_version, 'future') if supported_versions: assert version_string in supported_versions return version_string @@ -62,26 +62,28 @@ class MacPort(WebKitPort): """WebKit Mac implementation of the Port class.""" # FIXME: 'wk2' probably shouldn't be a version, it should probably be # a modifier, like 'chromium-gpu' is to 'chromium'. - SUPPORTED_VERSIONS = ('tiger', 'leopard', 'snowleopard', 'wk2') + SUPPORTED_VERSIONS = ('tiger', 'leopard', 'snowleopard', 'future', 'wk2') FALLBACK_PATHS = { 'tiger': ['mac-tiger', 'mac-leopard', 'mac-snowleopard', 'mac'], 'leopard': ['mac-leopard', 'mac-snowleopard', 'mac'], 'snowleopard': ['mac-snowleopard', 'mac'], + 'future': ['mac'], 'wk2': ['mac-wk2', 'mac'], } def __init__(self, port_name=None, os_version_string=None, **kwargs): port_name = port_name or 'mac' - + WebKitPort.__init__(self, port_name=port_name, **kwargs) if port_name == 'mac': self._version = os_version(os_version_string) - port_name = port_name + '-' + self._version + self._name = port_name + '-' + self._version else: self._version = port_name[4:] assert self._version in self.SUPPORTED_VERSIONS - - WebKitPort.__init__(self, port_name=port_name, **kwargs) + self._operating_system = 'mac' + if not hasattr(self._options, 'time-out-ms') or self._options.time_out_ms is None: + self._options.time_out_ms = 35000 def default_child_processes(self): # FIXME: new-run-webkit-tests is unstable on Mac running more than @@ -92,10 +94,12 @@ class MacPort(WebKitPort): return 4 return child_processes - def default_worker_model(self): - if self._multiprocessing_is_available: - return 'processes' - return 'threads' + def baseline_path(self): + if self.version() != 'future': + return WebKitPort.baseline_path(self) + + assert(self._name[-7:] == '-future') + return self._webkit_baseline_path(self._name[:-7]) def baseline_search_path(self): return map(self._webkit_baseline_path, self.FALLBACK_PATHS[self._version]) @@ -115,12 +119,6 @@ class MacPort(WebKitPort): 'Skipped')) return skipped_files - def test_platform_name(self): - return 'mac-' + self.version() - - def version(self): - return self._version - def _build_java_test_support(self): java_tests_path = self._filesystem.join(self.layout_tests_dir(), "java") build_java = ["/usr/bin/make", "-C", java_tests_path] @@ -132,24 +130,13 @@ class MacPort(WebKitPort): def _check_port_build(self): return self._build_java_test_support() - def _tests_for_other_platforms(self): - # The original run-webkit-tests builds up a "whitelist" of tests to - # run, and passes that to DumpRenderTree. new-run-webkit-tests assumes - # we run *all* tests and test_expectations.txt functions as a - # blacklist. - # FIXME: This list could be dynamic based on platform name and - # pushed into base.Port. - return [ - "platform/chromium", - "platform/gtk", - "platform/qt", - "platform/win", - ] - def _path_to_apache_config_file(self): return self._filesystem.join(self.layout_tests_dir(), 'http', 'conf', 'apache2-httpd.conf') + def _path_to_webcore_library(self): + return self._build_path('WebCore.framework/Versions/A/WebCore') + # FIXME: This doesn't have anything to do with WebKit. def _shut_down_http_server(self, server_pid): """Shut down the lighttpd web server. Blocks until it's fully diff --git a/Tools/Scripts/webkitpy/layout_tests/port/mac_unittest.py b/Tools/Scripts/webkitpy/layout_tests/port/mac_unittest.py index 4586a23..8906154 100644 --- a/Tools/Scripts/webkitpy/layout_tests/port/mac_unittest.py +++ b/Tools/Scripts/webkitpy/layout_tests/port/mac_unittest.py @@ -84,10 +84,22 @@ svg/batik/text/smallFonts.svg os_version_string=os_version_string) self.assertEquals(expected, port.name()) + def test_tests_for_other_platforms(self): + port = mac.MacPort(port_name='mac-snowleopard') + dirs_to_skip = port._tests_for_other_platforms() + self.assertTrue('platform/chromium-linux' in dirs_to_skip) + self.assertTrue('platform/mac-tiger' in dirs_to_skip) + self.assertFalse('platform/mac' in dirs_to_skip) + self.assertFalse('platform/mac-snowleopard' in dirs_to_skip) + + def test_version(self): + port = mac.MacPort() + self.assertTrue(port.version()) + def test_versions(self): port = self.make_port() if port: - self.assertTrue(port.name() in ('mac-tiger', 'mac-leopard', 'mac-snowleopard')) + self.assertTrue(port.name() in ('mac-tiger', 'mac-leopard', 'mac-snowleopard', 'mac-future')) self.assert_name(None, '10.4.8', 'mac-tiger') self.assert_name('mac', '10.4.8', 'mac-tiger') @@ -107,8 +119,16 @@ svg/batik/text/smallFonts.svg self.assert_name('mac-snowleopard', '10.5.3', 'mac-snowleopard') self.assert_name('mac-snowleopard', '10.6.3', 'mac-snowleopard') - self.assertRaises(KeyError, self.assert_name, None, '10.7.1', 'mac-leopard') - self.assertRaises(KeyError, self.assert_name, None, '10.3.1', 'mac-leopard') + self.assert_name(None, '10.7', 'mac-future') + self.assert_name(None, '10.7.3', 'mac-future') + self.assert_name(None, '10.8', 'mac-future') + self.assert_name('mac', '10.7.3', 'mac-future') + self.assert_name('mac-future', '10.4.3', 'mac-future') + self.assert_name('mac-future', '10.5.3', 'mac-future') + self.assert_name('mac-future', '10.6.3', 'mac-future') + self.assert_name('mac-future', '10.7.3', 'mac-future') + + self.assertRaises(AssertionError, self.assert_name, None, '10.3.1', 'should-raise-assertion-so-this-value-does-not-matter') if __name__ == '__main__': diff --git a/Tools/Scripts/webkitpy/layout_tests/port/mock_drt.py b/Tools/Scripts/webkitpy/layout_tests/port/mock_drt.py index 1147846..73967cf 100644 --- a/Tools/Scripts/webkitpy/layout_tests/port/mock_drt.py +++ b/Tools/Scripts/webkitpy/layout_tests/port/mock_drt.py @@ -32,6 +32,7 @@ This is an implementation of the Port interface that overrides other ports and changes the Driver binary to "MockDRT". """ +import base64 import logging import optparse import os @@ -206,15 +207,23 @@ class MockDRT(object): test_path = test_input.uri actual_text = port.expected_text(test_path) + actual_audio = port.expected_audio(test_path) if self._options.pixel_tests and test_input.checksum: actual_checksum = port.expected_checksum(test_path) actual_image = port.expected_image(test_path) - self._stdout.write('Content-Type: text/plain\n') + if actual_audio: + self._stdout.write('Content-Type: audio/wav\n') + self._stdout.write('Content-Transfer-Encoding: base64\n') + output = base64.b64encode(actual_audio) + self._stdout.write('Content-Length: %s\n' % len(output)) + self._stdout.write(output) + else: + self._stdout.write('Content-Type: text/plain\n') + # FIXME: Note that we don't ensure there is a trailing newline! + # This mirrors actual (Mac) DRT behavior but is a bug. + self._stdout.write(actual_text) - # FIXME: Note that we don't ensure there is a trailing newline! - # This mirrors actual (Mac) DRT behavior but is a bug. - self._stdout.write(actual_text) self._stdout.write('#EOF\n') if self._options.pixel_tests and test_input.checksum: @@ -223,7 +232,7 @@ class MockDRT(object): self._stdout.write('ExpectedHash: %s\n' % test_input.checksum) if actual_checksum != test_input.checksum: self._stdout.write('Content-Type: image/png\n') - self._stdout.write('Content-Length: %s\n\n' % len(actual_image)) + self._stdout.write('Content-Length: %s\n' % len(actual_image)) self._stdout.write(actual_image) self._stdout.write('#EOF\n') self._stdout.flush() diff --git a/Tools/Scripts/webkitpy/layout_tests/port/mock_drt_unittest.py b/Tools/Scripts/webkitpy/layout_tests/port/mock_drt_unittest.py index b6f6e8a..c489e20 100644 --- a/Tools/Scripts/webkitpy/layout_tests/port/mock_drt_unittest.py +++ b/Tools/Scripts/webkitpy/layout_tests/port/mock_drt_unittest.py @@ -39,13 +39,17 @@ from webkitpy.layout_tests.port import factory from webkitpy.layout_tests.port import port_testcase from webkitpy.layout_tests.port import test +from webkitpy.tool import mocktool +mock_options = mocktool.MockOptions(use_apache=True, + configuration='Release') + class MockDRTPortTest(port_testcase.PortTestCase): - def make_port(self): + def make_port(self, options=mock_options): if sys.platform == 'win32': # We use this because the 'win' port doesn't work yet. - return mock_drt.MockDRTPort(port_name='mock-chromium-win') - return mock_drt.MockDRTPort() + return mock_drt.MockDRTPort(port_name='mock-chromium-win', options=options) + return mock_drt.MockDRTPort(options=options) def test_default_worker_model(self): # only overridding the default test; we don't care about this one. @@ -200,7 +204,7 @@ class MockDRTTest(unittest.TestCase): 'ActualHash: checksum-checksum\n', 'ExpectedHash: wrong-checksum\n', 'Content-Type: image/png\n', - 'Content-Length: 13\n\n', + 'Content-Length: 13\n', 'checksum\x8a-png', '#EOF\n']) diff --git a/Tools/Scripts/webkitpy/layout_tests/port/port_testcase.py b/Tools/Scripts/webkitpy/layout_tests/port/port_testcase.py index 649e33c..cb1b915 100644 --- a/Tools/Scripts/webkitpy/layout_tests/port/port_testcase.py +++ b/Tools/Scripts/webkitpy/layout_tests/port/port_testcase.py @@ -38,8 +38,7 @@ except ImportError: multiprocessing = None from webkitpy.tool import mocktool -mock_options = mocktool.MockOptions(results_directory='layout-test-results', - use_apache=True, +mock_options = mocktool.MockOptions(use_apache=True, configuration='Release') # FIXME: This should be used for all ports, not just WebKit Mac. See @@ -60,10 +59,7 @@ class PortTestCase(unittest.TestCase): if not maker: return None - port = maker(options=options) - if hasattr(options, "results_directory"): - port._options.results_directory = port.results_directory() - return port + return maker(options=options) def test_default_worker_model(self): port = self.make_port() @@ -81,6 +77,12 @@ class PortTestCase(unittest.TestCase): return self.assertTrue(len(port.driver_cmd_line())) + options = mocktool.MockOptions(additional_drt_flag=['--foo=bar', '--foo=baz']) + port = self.make_port(options=options) + cmd_line = port.driver_cmd_line() + self.assertTrue('--foo=bar' in cmd_line) + self.assertTrue('--foo=baz' in cmd_line) + def disabled_test_http_server(self): port = self.make_port() if not port: @@ -113,6 +115,30 @@ class PortTestCase(unittest.TestCase): port._filesystem.remove(tmpfile) + def test_diff_image__missing_both(self): + port = self.make_port() + if not port: + return + self.assertFalse(port.diff_image(None, None, None)) + self.assertFalse(port.diff_image(None, '', None)) + self.assertFalse(port.diff_image('', None, None)) + self.assertFalse(port.diff_image('', '', None)) + + def test_diff_image__missing_actual(self): + port = self.make_port() + if not port: + return + self.assertTrue(port.diff_image(None, 'foo', None)) + self.assertTrue(port.diff_image('', 'foo', None)) + + def test_diff_image__missing_expected(self): + port = self.make_port() + if not port: + return + self.assertTrue(port.diff_image('foo', None, None)) + self.assertTrue(port.diff_image('foo', '', None)) + + def disabled_test_websocket_server(self): port = self.make_port() if not port: diff --git a/Tools/Scripts/webkitpy/layout_tests/port/test.py b/Tools/Scripts/webkitpy/layout_tests/port/test.py index 392818d..fed7e11 100644 --- a/Tools/Scripts/webkitpy/layout_tests/port/test.py +++ b/Tools/Scripts/webkitpy/layout_tests/port/test.py @@ -30,6 +30,7 @@ """Dummy Port implementation used for testing.""" from __future__ import with_statement +import base64 import time from webkitpy.common.system import filesystem_mock @@ -66,6 +67,8 @@ class TestInstance: self.expected_checksum = self.actual_checksum self.expected_image = self.actual_image + self.actual_audio = None + self.expected_audio = None # This is an in-memory list of tests, what we want them to produce, and # what we want to claim are the expected results. @@ -111,11 +114,20 @@ def unit_test_list(): tests.add('failures/expected/image_checksum.html', actual_checksum='image_checksum_fail-checksum', actual_image='image_checksum_fail-png') + tests.add('failures/expected/audio.html', + actual_audio=base64.b64encode('audio_fail-wav'), expected_audio='audio-wav', + actual_text=None, expected_text=None, + actual_image=None, expected_image=None, + actual_checksum=None, expected_checksum=None) tests.add('failures/expected/keyboard.html', keyboard=True) tests.add('failures/expected/missing_check.html', expected_checksum=None, expected_image=None) tests.add('failures/expected/missing_image.html', expected_image=None) + tests.add('failures/expected/missing_audio.html', expected_audio=None, + actual_text=None, expected_text=None, + actual_image=None, expected_image=None, + actual_checksum=None, expected_checksum=None) tests.add('failures/expected/missing_text.html', expected_text=None) tests.add('failures/expected/newlines_leading.html', expected_text="\nfoo\n", actual_text="foo\n") @@ -134,6 +146,11 @@ def unit_test_list(): tests.add('http/tests/ssl/text.html') tests.add('passes/error.html', error='stuff going to stderr') tests.add('passes/image.html') + tests.add('passes/audio.html', + actual_audio=base64.b64encode('audio-wav'), expected_audio='audio-wav', + actual_text=None, expected_text=None, + actual_image=None, expected_image=None, + actual_checksum=None, expected_checksum=None) tests.add('passes/platform_image.html') tests.add('passes/checksum_in_image.html', expected_checksum=None, @@ -184,20 +201,27 @@ def unit_test_filesystem(files=None): add_file(files, test, '.html', '') if test.is_reftest: continue + if test.actual_audio: + add_file(files, test, '-expected.wav', test.expected_audio) + continue + add_file(files, test, '-expected.txt', test.expected_text) add_file(files, test, '-expected.checksum', test.expected_checksum) add_file(files, test, '-expected.png', test.expected_image) + # Add the test_expectations file. files[LAYOUT_TEST_DIR + '/platform/test/test_expectations.txt'] = """ WONTFIX : failures/expected/checksum.html = IMAGE WONTFIX : failures/expected/crash.html = CRASH // This one actually passes because the checksums will match. WONTFIX : failures/expected/image.html = PASS +WONTFIX : failures/expected/audio.html = AUDIO WONTFIX : failures/expected/image_checksum.html = IMAGE WONTFIX : failures/expected/mismatch.html = IMAGE WONTFIX : failures/expected/missing_check.html = MISSING PASS WONTFIX : failures/expected/missing_image.html = MISSING PASS +WONTFIX : failures/expected/missing_audio.html = MISSING PASS WONTFIX : failures/expected/missing_text.html = MISSING PASS WONTFIX : failures/expected/newlines_leading.html = TEXT WONTFIX : failures/expected/newlines_trailing.html = TEXT @@ -220,23 +244,41 @@ WONTFIX SKIP : failures/expected/exception.html = CRASH class TestPort(base.Port): """Test implementation of the Port interface.""" + ALL_BASELINE_VARIANTS = ( + 'test-mac-snowleopard', 'test-mac-leopard', + 'test-win-win7', 'test-win-vista', 'test-win-xp', + 'test-linux-x86', + ) def __init__(self, port_name=None, user=None, filesystem=None, **kwargs): - if not filesystem: - filesystem = unit_test_filesystem() + if not port_name or port_name == 'test': + port_name = 'test-mac-leopard' + user = user or mocktool.MockUser() + filesystem = filesystem or unit_test_filesystem() + base.Port.__init__(self, port_name=port_name, filesystem=filesystem, user=user, + **kwargs) + self._results_directory = None assert filesystem._tests self._tests = filesystem._tests - if not user: - user = mocktool.MockUser() + self._operating_system = 'mac' + if port_name.startswith('test-win'): + self._operating_system = 'win' + elif port_name.startswith('test-linux'): + self._operating_system = 'linux' - if not port_name or port_name == 'test': - port_name = 'test-mac' + version_map = { + 'test-win-xp': 'xp', + 'test-win-win7': 'win7', + 'test-win-vista': 'vista', + 'test-mac-leopard': 'leopard', + 'test-mac-snowleopard': 'snowleopard', + 'test-linux-x86': '', + } + self._version = version_map[port_name] self._expectations_path = LAYOUT_TEST_DIR + '/platform/test/test_expectations.txt' - base.Port.__init__(self, port_name=port_name, filesystem=filesystem, user=user, - **kwargs) def _path_to_driver(self): # This routine shouldn't normally be called, but it is called by @@ -248,7 +290,15 @@ class TestPort(base.Port): return self._filesystem.join(self.layout_tests_dir(), 'platform', self.name()) def baseline_search_path(self): - return [self.baseline_path()] + search_paths = { + 'test-mac-snowleopard': ['test-mac-snowleopard'], + 'test-mac-leopard': ['test-mac-leopard', 'test-mac-snowleopard'], + 'test-win-win7': ['test-win-win7'], + 'test-win-vista': ['test-win-vista', 'test-win-win7'], + 'test-win-xp': ['test-win-xp', 'test-win-vista', 'test-win-win7'], + 'test-linux-x86': ['test-linux', 'test-win-win7'], + } + return [self._webkit_baseline_path(d) for d in search_paths[self.name()]] def default_child_processes(self): return 1 @@ -279,8 +329,8 @@ class TestPort(base.Port): def _path_to_wdiff(self): return None - def results_directory(self): - return '/tmp/' + self.get_option('results_directory') + def default_results_directory(self): + return '/tmp/layout-test-results' def setup_test_run(self): pass @@ -303,24 +353,8 @@ class TestPort(base.Port): def path_to_test_expectations_file(self): return self._expectations_path - def test_platform_name(self): - name_map = { - 'test-mac': 'mac', - 'test-win': 'win', - 'test-win-xp': 'win-xp', - } - return name_map[self._name] - - def test_platform_names(self): - return ('mac', 'win', 'win-xp') - - def test_platform_name_to_name(self, test_platform_name): - name_map = { - 'mac': 'test-mac', - 'win': 'test-win', - 'win-xp': 'test-win-xp', - } - return name_map[test_platform_name] + def all_baseline_variants(self): + return self.ALL_BASELINE_VARIANTS # FIXME: These next two routines are copied from base.py with # the calls to path.abspath_to_uri() removed. We shouldn't have @@ -380,19 +414,6 @@ class TestPort(base.Port): raise NotImplementedError('unknown url type: %s' % uri) - def version(self): - version_map = { - 'test-win-xp': 'xp', - 'test-win': 'win7', - 'test-mac': 'leopard', - } - return version_map[self._name] - - def test_configuration(self): - if not self._test_configuration: - self._test_configuration = TestTestConfiguration(self) - return self._test_configuration - class TestDriver(base.Driver): """Test/Dummy implementation of the DumpRenderTree interface.""" @@ -401,7 +422,7 @@ class TestDriver(base.Driver): self._port = port def cmd_line(self): - return [self._port._path_to_driver()] + return [self._port._path_to_driver()] + self._port.get_option('additional_drt_flag', []) def poll(self): return True @@ -416,20 +437,16 @@ class TestDriver(base.Driver): raise ValueError('exception from ' + test_name) if test.hang: time.sleep((float(test_input.timeout) * 4) / 1000.0) + + audio = None + if test.actual_audio: + audio = base64.b64decode(test.actual_audio) return base.DriverOutput(test.actual_text, test.actual_image, - test.actual_checksum, test.crash, - time.time() - start_time, test.timeout, - test.error) + test.actual_checksum, audio, crash=test.crash, + test_time=time.time() - start_time, timeout=test.timeout, error=test.error) def start(self): pass def stop(self): pass - - -class TestTestConfiguration(base.TestConfiguration): - def all_systems(self): - return (('mac', 'leopard', 'x86'), - ('win', 'xp', 'x86'), - ('win', 'win7', 'x86')) diff --git a/Tools/Scripts/webkitpy/layout_tests/port/webkit.py b/Tools/Scripts/webkitpy/layout_tests/port/webkit.py index 65a047d..4ac4a13 100644 --- a/Tools/Scripts/webkitpy/layout_tests/port/webkit.py +++ b/Tools/Scripts/webkitpy/layout_tests/port/webkit.py @@ -30,7 +30,7 @@ """WebKit implementations of the Port interface.""" - +import base64 import logging import operator import os @@ -69,10 +69,6 @@ class WebKitPort(base.Port): return self._filesystem.join(self._webkit_baseline_path(self._name), 'test_expectations.txt') - # Only needed by ports which maintain versioned test expectations (like mac-tiger vs. mac-leopard) - def version(self): - return '' - def _build_driver(self): configuration = self.get_option('configuration') return self._config.build_dumprendertree(configuration) @@ -113,7 +109,10 @@ class WebKitPort(base.Port): image of the two images into |diff_filename| if it is not None.""" # Handle the case where the test didn't actually generate an image. - if not actual_contents: + # FIXME: need unit tests for this. + if not actual_contents and not expected_contents: + return False + if not actual_contents or not expected_contents: return True sp = self._diff_image_request(expected_contents, actual_contents) @@ -167,10 +166,10 @@ class WebKitPort(base.Port): sp.stop() return result - def results_directory(self): + def default_results_directory(self): # Results are store relative to the built products to make it easy # to have multiple copies of webkit checked out and built. - return self._build_path(self.get_option('results_directory')) + return self._build_path('layout-test-results') def setup_test_run(self): # This port doesn't require any specific configuration. @@ -180,19 +179,17 @@ class WebKitPort(base.Port): return WebKitDriver(self, worker_number) def _tests_for_other_platforms(self): - raise NotImplementedError('WebKitPort._tests_for_other_platforms') - # The original run-webkit-tests builds up a "whitelist" of tests to - # run, and passes that to DumpRenderTree. new-run-webkit-tests assumes - # we run *all* tests and test_expectations.txt functions as a - # blacklist. - # FIXME: This list could be dynamic based on platform name and - # pushed into base.Port. - return [ - "platform/chromium", - "platform/gtk", - "platform/qt", - "platform/win", - ] + # By default we will skip any directory under LayoutTests/platform + # that isn't in our baseline search path (this mirrors what + # old-run-webkit-tests does in findTestsToRun()). + # Note this returns LayoutTests/platform/*, not platform/*/*. + entries = self._filesystem.glob(self._webkit_baseline_path('*')) + dirs_to_skip = [] + for entry in entries: + if self._filesystem.isdir(entry) and not entry in self.baseline_search_path(): + basename = self._filesystem.basename(entry) + dirs_to_skip.append('platform/%s' % basename) + return dirs_to_skip def _runtime_feature_list(self): """Return the supported features of DRT. If a port doesn't support @@ -327,12 +324,6 @@ class WebKitPort(base.Port): tests_to_skip.update(self._tests_for_disabled_features()) return tests_to_skip - def test_platform_name(self): - return self._name + self.version() - - def test_platform_names(self): - return ('mac', 'win', 'mac-tiger', 'mac-leopard', 'mac-snowleopard') - def _build_path(self, *comps): return self._filesystem.join(self._config.build_directory( self.get_option('configuration')), *comps) @@ -381,11 +372,11 @@ class WebKitDriver(base.Driver): def cmd_line(self): cmd = self._command_wrapper(self._port.get_option('wrapper')) - cmd += [self._port._path_to_driver(), '-'] - + cmd.append(self._port._path_to_driver()) if self._port.get_option('pixel_tests'): cmd.append('--pixel-tests') - + cmd.extend(self._port.get_option('additional_drt_flag', [])) + cmd.append('-') return cmd def start(self): @@ -418,47 +409,24 @@ class WebKitDriver(base.Driver): start_time = time.time() self._server_process.write(command) - have_seen_content_type = False + text = None + image = None actual_image_hash = None - output = str() # Use a byte array for output, even though it should be UTF-8. - image = str() + audio = None + deadline = time.time() + int(driver_input.timeout) / 1000.0 - timeout = int(driver_input.timeout) / 1000.0 - deadline = time.time() + timeout - line = self._server_process.read_line(timeout) - while (not self._server_process.timed_out - and not self._server_process.crashed - and line.rstrip() != "#EOF"): - if (line.startswith('Content-Type:') and not - have_seen_content_type): - have_seen_content_type = True - else: - # Note: Text output from DumpRenderTree is always UTF-8. - # However, some tests (e.g. webarchives) spit out binary - # data instead of text. So to make things simple, we - # always treat the output as binary. - output += line - line = self._server_process.read_line(timeout) - timeout = deadline - time.time() + # First block is either text or audio + block = self._read_block(deadline) + if block.content_type == 'audio/wav': + audio = block.decoded_content + else: + text = block.decoded_content - # Now read a second block of text for the optional image data - remaining_length = -1 - HASH_HEADER = 'ActualHash: ' - LENGTH_HEADER = 'Content-Length: ' - line = self._server_process.read_line(timeout) - while (not self._server_process.timed_out - and not self._server_process.crashed - and line.rstrip() != "#EOF"): - if line.startswith(HASH_HEADER): - actual_image_hash = line[len(HASH_HEADER):].strip() - elif line.startswith('Content-Type:'): - pass - elif line.startswith(LENGTH_HEADER): - timeout = deadline - time.time() - content_length = int(line[len(LENGTH_HEADER):]) - image = self._server_process.read(timeout, content_length) - timeout = deadline - time.time() - line = self._server_process.read_line(timeout) + # Now read an optional second block of image data + block = self._read_block(deadline) + if block.content and block.content_type == 'image/png': + image = block.decoded_content + actual_image_hash = block.content_hash error_lines = self._server_process.error.splitlines() # FIXME: This is a hack. It is unclear why sometimes @@ -470,13 +438,59 @@ class WebKitDriver(base.Driver): # FIXME: This seems like the wrong section of code to be doing # this reset in. self._server_process.error = "" - return base.DriverOutput(output, image, actual_image_hash, - self._server_process.crashed, - time.time() - start_time, - self._server_process.timed_out, - error) + return base.DriverOutput(text, image, actual_image_hash, audio, + crash=self._server_process.crashed, test_time=time.time() - start_time, + timeout=self._server_process.timed_out, error=error) + + def _read_block(self, deadline): + LENGTH_HEADER = 'Content-Length: ' + HASH_HEADER = 'ActualHash: ' + TYPE_HEADER = 'Content-Type: ' + ENCODING_HEADER = 'Content-Transfer-Encoding: ' + content_type = None + encoding = None + content_hash = None + content_length = None + + # Content is treated as binary data even though the text output + # is usually UTF-8. + content = '' + timeout = deadline - time.time() + line = self._server_process.read_line(timeout) + while (not self._server_process.timed_out + and not self._server_process.crashed + and line.rstrip() != "#EOF"): + if line.startswith(TYPE_HEADER) and content_type is None: + content_type = line.split()[1] + elif line.startswith(ENCODING_HEADER) and encoding is None: + encoding = line.split()[1] + elif line.startswith(LENGTH_HEADER) and content_length is None: + timeout = deadline - time.time() + content_length = int(line[len(LENGTH_HEADER):]) + # FIXME: Technically there should probably be another blank + # line here, but DRT doesn't write one. + content = self._server_process.read(timeout, content_length) + elif line.startswith(HASH_HEADER): + content_hash = line.split()[1] + else: + content += line + line = self._server_process.read_line(timeout) + timeout = deadline - time.time() + return ContentBlock(content_type, encoding, content_hash, content) def stop(self): if self._server_process: self._server_process.stop() self._server_process = None + + +class ContentBlock(object): + def __init__(self, content_type, encoding, content_hash, content): + self.content_type = content_type + self.encoding = encoding + self.content_hash = content_hash + self.content = content + if self.encoding == 'base64': + self.decoded_content = base64.b64decode(content) + else: + self.decoded_content = content diff --git a/Tools/Scripts/webkitpy/layout_tests/port/webkit_unittest.py b/Tools/Scripts/webkitpy/layout_tests/port/webkit_unittest.py index c72a411..ef1a1c2 100644 --- a/Tools/Scripts/webkitpy/layout_tests/port/webkit_unittest.py +++ b/Tools/Scripts/webkitpy/layout_tests/port/webkit_unittest.py @@ -30,6 +30,7 @@ import unittest from webkitpy.common.system import filesystem_mock from webkitpy.layout_tests.port.webkit import WebKitPort +from webkitpy.layout_tests.port import port_testcase class TestWebKitPort(WebKitPort): @@ -63,7 +64,18 @@ class TestWebKitPort(WebKitPort): return [self.skips_file] return [] -class WebKitPortTest(unittest.TestCase): + +class WebKitPortTest(port_testcase.PortTestCase): + def port_maker(self, platform): + return WebKitPort + + def test_driver_cmd_line(self): + # Routine is not implemented. + pass + + def test_baseline_search_path(self): + # Routine is not implemented. + pass def test_skipped_directories_for_symbols(self): supported_symbols = ["GraphicsLayer", "WebCoreHas3DRendering", "isXHTMLMPDocument", "fooSymbol"] diff --git a/Tools/Scripts/webkitpy/layout_tests/port/win.py b/Tools/Scripts/webkitpy/layout_tests/port/win.py index e7d2004..03a76f4 100644 --- a/Tools/Scripts/webkitpy/layout_tests/port/win.py +++ b/Tools/Scripts/webkitpy/layout_tests/port/win.py @@ -38,9 +38,11 @@ _log = logging.getLogger("webkitpy.layout_tests.port.win") class WinPort(WebKitPort): """WebKit Win implementation of the Port class.""" - def __init__(self, **kwargs): - kwargs.setdefault('port_name', 'win') - WebKitPort.__init__(self, **kwargs) + def __init__(self, port_name=None, **kwargs): + port_name = port_name or 'win' + WebKitPort.__init__(self, port_name=port_name, **kwargs) + self._version = 'win7' + self._operating_system = 'win' def baseline_search_path(self): # Based on code from old-run-webkit-tests expectedDirectoryForTest() diff --git a/Tools/Scripts/webkitpy/layout_tests/rebaseline_chromium_webkit_tests.py b/Tools/Scripts/webkitpy/layout_tests/rebaseline_chromium_webkit_tests.py index 9f1d347..50a7374 100644 --- a/Tools/Scripts/webkitpy/layout_tests/rebaseline_chromium_webkit_tests.py +++ b/Tools/Scripts/webkitpy/layout_tests/rebaseline_chromium_webkit_tests.py @@ -41,6 +41,8 @@ The script does the following for each platform specified: At the end, the script generates a html that compares old and new baselines. """ +from __future__ import with_statement + import copy import logging import optparse @@ -55,27 +57,26 @@ from webkitpy.common.system import urlfetcher from webkitpy.common.system.executive import ScriptError from webkitpy.layout_tests import port +from webkitpy.layout_tests import read_checksum_from_png from webkitpy.layout_tests.layout_package import test_expectations _log = logging.getLogger(__name__) BASELINE_SUFFIXES = ('.txt', '.png', '.checksum') -REBASELINE_PLATFORM_ORDER = ('mac', 'win', 'win-xp', 'win-vista', 'linux') -ARCHIVE_DIR_NAME_DICT = {'win': 'Webkit_Win__deps_', - 'win-vista': 'webkit-dbg-vista', - 'win-xp': 'Webkit_Win__deps_', - 'mac': 'Webkit_Mac10_5__deps_', - 'linux': 'Webkit_Linux__deps_', - - 'win-canary': 'Webkit_Win', - 'win-vista-canary': 'webkit-dbg-vista', - 'win-xp-canary': 'Webkit_Win', - 'mac-canary': 'Webkit_Mac10_5', - 'linux-canary': 'Webkit_Linux', - - 'gpu-mac-canary': 'Webkit_Mac10_5_-_GPU', - 'gpu-win-canary': 'Webkit_Win_-_GPU', - 'gpu-linux-canary': 'Webkit_Linux_-_GPU', + +ARCHIVE_DIR_NAME_DICT = { + 'chromium-win-win7': 'Webkit_Win7', + 'chromium-win-vista': 'Webkit_Vista', + 'chromium-win-xp': 'Webkit_Win', + 'chromium-mac-leopard': 'Webkit_Mac10_5', + 'chromium-mac-snowleopard': 'Webkit_Mac10_6', + 'chromium-linux-x86': 'Webkit_Linux', + 'chromium-linux-x86_64': 'Webkit_Linux_64', + 'chromium-gpu-mac-snowleopard': 'Webkit_Mac10_6_-_GPU', + 'chromium-gpu-win-xp': 'Webkit_Win_-_GPU', + 'chromium-gpu-win-win7': 'Webkit_Win7_-_GPU', + 'chromium-gpu-linux': 'Webkit_Linux_-_GPU', + 'chromium-gpu-linux-x86_64': 'Webkit_Linux_64_-_GPU', } @@ -166,11 +167,7 @@ class Rebaseliner(object): self._filesystem = running_port._filesystem self._target_port = target_port - # FIXME: See the comments in chromium_{win,mac}.py about why we need - # the 'rebaselining' keyword. - self._rebaseline_port = port.get( - self._target_port.test_platform_name_to_name(platform), options, - filesystem=self._filesystem, rebaselining=True) + self._rebaseline_port = port.get(platform, options, filesystem=self._filesystem) self._rebaselining_tests = set() self._rebaselined_tests = [] @@ -185,13 +182,13 @@ class Rebaseliner(object): self._zip_factory = zip_factory self._scm = scm - def run(self, backup): + def run(self): """Run rebaseline process.""" log_dashed_string('Compiling rebaselining tests', self._platform) if not self._compile_rebaselining_tests(): return False - if not self.get_rebaselining_tests(): + if not self._rebaselining_tests: return True log_dashed_string('Downloading archive', self._platform) @@ -209,8 +206,6 @@ class Rebaseliner(object): archive_file.close() log_dashed_string('Updating rebaselined tests in file', self._platform) - self._update_rebaselined_tests_in_file(backup) - _log.info('') if len(self._rebaselining_tests) != len(self._rebaselined_tests): _log.warning('NOT ALL TESTS THAT NEED REBASELINING HAVE BEEN REBASELINED.') @@ -222,8 +217,23 @@ class Rebaseliner(object): return True - def get_rebaselining_tests(self): - return self._rebaselining_tests + def remove_rebaselining_expectations(self, tests, backup): + """if backup is True, we backup the original test expectations file.""" + new_expectations = self._test_expectations.remove_rebaselined_tests(tests) + path = self._target_port.path_to_test_expectations_file() + if backup: + date_suffix = time.strftime('%Y%m%d%H%M%S', time.localtime(time.time())) + backup_file = '%s.orig.%s' % (path, date_suffix) + if self._filesystem.exists(backup_file): + self._filesystem.remove(backup_file) + _log.info('Saving original file to "%s"', backup_file) + self._filesystem.move(path, backup_file) + + self._filesystem.write_text_file(path, new_expectations) + # self._scm.add(path) + + def get_rebaselined_tests(self): + return self._rebaselined_tests def _compile_rebaselining_tests(self): """Compile list of tests that need rebaselining for the platform. @@ -232,8 +242,7 @@ class Rebaseliner(object): False if reftests are wrongly marked as 'needs rebaselining' or True """ - self._rebaselining_tests = \ - self._test_expectations.get_rebaselining_failures() + self._rebaselining_tests = self._test_expectations.get_rebaselining_failures() if not self._rebaselining_tests: _log.warn('No tests found that need rebaselining.') return True @@ -307,13 +316,7 @@ class Rebaseliner(object): if self._options.force_archive_url: return self._options.force_archive_url - platform = self._platform - if self._options.webkit_canary: - platform += '-canary' - if self._options.gpu: - platform = 'gpu-' + platform - - dir_name = self._get_archive_dir_name(platform) + dir_name = self._get_archive_dir_name(self._platform) if not dir_name: return None @@ -349,8 +352,7 @@ class Rebaseliner(object): for name in zip_namelist: _log.debug(' ' + name) - platform = self._rebaseline_port.test_platform_name_to_name(self._platform) - _log.debug('Platform dir: "%s"', platform) + _log.debug('Platform dir: "%s"', self._platform) self._rebaselined_tests = [] for test_no, test in enumerate(self._rebaselining_tests): @@ -392,6 +394,12 @@ class Rebaseliner(object): self._delete_baseline(expected_fullpath) continue + if suffix == '.checksum' and self._png_has_same_checksum(temp_name, test, expected_fullpath): + self._filesystem.remove(temp_name) + # If an old checksum exists, delete it. + self._delete_baseline(expected_fullpath) + continue + self._filesystem.maybe_make_directory(self._filesystem.dirname(expected_fullpath)) self._filesystem.move(temp_name, expected_fullpath) @@ -419,15 +427,40 @@ class Rebaseliner(object): tempfile.close() return temp_name - def _is_dup_baseline(self, new_baseline, baseline_path, test, suffix, - platform): + def _png_has_same_checksum(self, checksum_path, test, checksum_expected_fullpath): + """Returns True if the fallback png for |checksum_expected_fullpath| + contains the same checksum.""" + fs = self._filesystem + png_fullpath = self._first_fallback_png_for_test(test) + + if not fs.exists(png_fullpath): + _log.error(' Checksum without png file found! Expected %s to exist.' % png_fullpath) + return False + + with fs.open_binary_file_for_reading(png_fullpath) as filehandle: + checksum_in_png = read_checksum_from_png.read_checksum(filehandle) + checksum_in_text_file = fs.read_text_file(checksum_path) + if checksum_in_png and checksum_in_png != checksum_in_text_file: + _log.error(" checksum in %s and %s don't match! Continuing" + " to copy but please investigate." % ( + checksum_expected_fullpath, png_fullpath)) + return checksum_in_text_file == checksum_in_png + + def _first_fallback_png_for_test(self, test): + test_filepath = self._filesystem.join(self._target_port.layout_tests_dir(), test) + all_baselines = self._rebaseline_port.expected_baselines( + test_filepath, '.png', True) + return self._filesystem.join(all_baselines[0][0], all_baselines[0][1]) + + def _is_dup_baseline(self, new_baseline, baseline_path, test, suffix, platform): """Check whether a baseline is duplicate and can fallback to same baseline for another platform. For example, if a test has same baseline on linux and windows, then we only store windows baseline and linux baseline will fallback to the windows version. Args: - expected_filename: baseline expectation file name. + new_baseline: temp filename containing the new baseline results + baseline_path: baseline expectation file name. test: test name. suffix: file suffix of the expected results, including dot; e.g. '.txt' or '.png'. @@ -487,33 +520,6 @@ class Rebaseliner(object): return self._scm.delete(filename) - def _update_rebaselined_tests_in_file(self, backup): - """Update the rebaselined tests in test expectations file. - - Args: - backup: if True, backup the original test expectations file. - - Returns: - no - """ - - if self._rebaselined_tests: - new_expectations = self._test_expectations.remove_platform_from_expectations( - self._rebaselined_tests, self._platform) - path = self._target_port.path_to_test_expectations_file() - if backup: - date_suffix = time.strftime('%Y%m%d%H%M%S', time.localtime(time.time())) - backup_file = '%s.orig.%s' % (path, date_suffix) - if self._filesystem.exists(backup_file): - self._filesystem.remove(backup_file) - _log.info('Saving original file to "%s"', backup_file) - self._filesystem.move(path, backup_file) - - self._filesystem.write_text_file(path, new_expectations) - # self._scm.add(path) - else: - _log.info('No test was rebaselined so nothing to remove.') - def _create_html_baseline_files(self, baseline_fullpath): """Create baseline files (old, new and diff) in html directory. @@ -792,10 +798,6 @@ def parse_options(args): action='store_true', help='Suppress result HTML viewing') - option_parser.add_option('-g', '--gpu', - action='store_true', default=False, - help='Rebaseline the GPU versions') - option_parser.add_option('-p', '--platforms', default=None, help=('Comma delimited list of platforms ' @@ -810,12 +812,6 @@ def parse_options(args): help=('Url of result zip file. This option is for debugging ' 'purposes')) - option_parser.add_option('-w', '--webkit_canary', - action='store_true', - default=False, - help=('If True, pull baselines from webkit.org ' - 'canary bot.')) - option_parser.add_option('-b', '--backup', action='store_true', default=False, @@ -833,17 +829,21 @@ def parse_options(args): help=('Use ImageDiff from DumpRenderTree instead ' 'of image_diff for pixel tests.')) + option_parser.add_option('-w', '--webkit_canary', + action='store_true', + default=False, + help=('DEPRECATED. This flag no longer has any effect.' + ' The canaries are always used.')) + option_parser.add_option('', '--target-platform', default='chromium', help=('The target platform to rebaseline ' '("mac", "chromium", "qt", etc.). Defaults ' 'to "chromium".')) + options = option_parser.parse_args(args)[0] - if options.platforms == None: - if options.gpu: - options.platforms = 'mac,win,linux' - else: - options.platforms = 'mac,win,win-xp,win-vista,linux' + if options.webkit_canary: + print "-w/--webkit-canary is no longer necessary, ignoring." target_options = copy.copy(options) if options.target_platform == 'chromium': @@ -866,10 +866,7 @@ def main(args): '%(levelname)s %(message)s'), datefmt='%y%m%d %H:%M:%S') - target_port_name = None - if options.gpu and options.target_platform == 'chromium': - target_port_name = 'chromium-gpu' - target_port_obj = port.get(target_port_name, target_options) + target_port_obj = port.get(None, target_options) host_port_obj = get_host_port_object(options) if not host_port_obj or not target_port_obj: return 1 @@ -906,30 +903,21 @@ def real_main(options, target_options, host_port_obj, target_port_obj, url_fetch the archives. scm_obj: object used to add new baselines to the source control system. """ - # Verify 'platforms' option is valid. - if not options.platforms: - _log.error('Invalid "platforms" option. --platforms must be ' - 'specified in order to rebaseline.') - return 1 - platforms = [p.strip().lower() for p in options.platforms.split(',')] - for platform in platforms: - if not platform in REBASELINE_PLATFORM_ORDER: - _log.error('Invalid platform: "%s"' % (platform)) - return 1 - - # Adjust the platform order so rebaseline tool is running at the order of - # 'mac', 'win' and 'linux'. This is in same order with layout test baseline - # search paths. It simplifies how the rebaseline tool detects duplicate - # baselines. Check _IsDupBaseline method for details. - rebaseline_platforms = [] - for platform in REBASELINE_PLATFORM_ORDER: - if platform in platforms: - rebaseline_platforms.append(platform) - options.html_directory = setup_html_directory(host_port_obj._filesystem, options.html_directory) + all_platforms = target_port_obj.all_baseline_variants() + if options.platforms: + bail = False + for platform in options.platforms: + if not platform in all_platforms: + _log.error('Invalid platform: "%s"' % (platform)) + bail = True + if bail: + return 1 + rebaseline_platforms = options.platforms + else: + rebaseline_platforms = all_platforms - rebaselining_tests = set() - backup = options.backup + rebaselined_tests = set() for platform in rebaseline_platforms: rebaseliner = Rebaseliner(host_port_obj, target_port_obj, platform, options, url_fetcher, zip_factory, @@ -937,14 +925,16 @@ def real_main(options, target_options, host_port_obj, target_port_obj, url_fetch _log.info('') log_dashed_string('Rebaseline started', platform) - if rebaseliner.run(backup): - # Only need to backup one original copy of test expectation file. - backup = False + if rebaseliner.run(): log_dashed_string('Rebaseline done', platform) else: log_dashed_string('Rebaseline failed', platform, logging.ERROR) - rebaselining_tests |= set(rebaseliner.get_rebaselining_tests()) + rebaselined_tests |= set(rebaseliner.get_rebaselined_tests()) + + if rebaselined_tests: + rebaseliner.remove_rebaselining_expectations(rebaselined_tests, + options.backup) _log.info('') log_dashed_string('Rebaselining result comparison started', None) @@ -952,7 +942,7 @@ def real_main(options, target_options, host_port_obj, target_port_obj, url_fetch target_port_obj, options, rebaseline_platforms, - rebaselining_tests) + rebaselined_tests) html_generator.generate_html() if not options.quiet: html_generator.show_html() diff --git a/Tools/Scripts/webkitpy/layout_tests/rebaseline_chromium_webkit_tests_unittest.py b/Tools/Scripts/webkitpy/layout_tests/rebaseline_chromium_webkit_tests_unittest.py index 7179bb7..73bc1a7 100644 --- a/Tools/Scripts/webkitpy/layout_tests/rebaseline_chromium_webkit_tests_unittest.py +++ b/Tools/Scripts/webkitpy/layout_tests/rebaseline_chromium_webkit_tests_unittest.py @@ -65,13 +65,9 @@ def test_options(): html_directory='/tmp', archive_url=ARCHIVE_URL, force_archive_url=None, - webkit_canary=True, - use_drt=False, - target_platform='chromium', verbose=False, quiet=False, - platforms='mac,win,win-xp', - gpu=False) + platforms=None) def test_host_port_and_filesystem(options, expectations): @@ -86,8 +82,12 @@ def test_host_port_and_filesystem(options, expectations): def test_url_fetcher(filesystem): urls = { + ARCHIVE_URL + '/Webkit_Mac10_6/': '<a href="4/">', ARCHIVE_URL + '/Webkit_Mac10_5/': '<a href="1/"><a href="2/">', + ARCHIVE_URL + '/Webkit_Win7/': '<a href="1/">', + ARCHIVE_URL + '/Webkit_Vista/': '<a href="1/">', ARCHIVE_URL + '/Webkit_Win/': '<a href="1/">', + ARCHIVE_URL + '/Webkit_Linux/': '<a href="1/">', } return urlfetcher_mock.make_fetcher_cls(urls)(filesystem) @@ -98,8 +98,31 @@ def test_zip_factory(): 'layout-test-results/failures/expected/image-actual.txt': 'new-image-txt', 'layout-test-results/failures/expected/image-actual.checksum': 'new-image-checksum', 'layout-test-results/failures/expected/image-actual.png': 'new-image-png', + 'layout-test-results/failures/expected/image_checksum-actual.txt': 'png-comment-txt', + 'layout-test-results/failures/expected/image_checksum-actual.checksum': '0123456789', + 'layout-test-results/failures/expected/image_checksum-actual.png': 'tEXtchecksum\x000123456789', }, - ARCHIVE_URL + '/Webkit_Win/1/layout-test-results.zip': { + ARCHIVE_URL + '/Webkit_Mac10_6/4/layout-test-results.zip': { + 'layout-test-results/failures/expected/image-actual.txt': 'new-image-txt', + 'layout-test-results/failures/expected/image-actual.checksum': 'new-image-checksum', + 'layout-test-results/failures/expected/image-actual.png': 'new-image-png', + }, + ARCHIVE_URL + '/Webkit_Vista/1/layout-test-results.zip': { + 'layout-test-results/failures/expected/image-actual.txt': 'win-image-txt', + 'layout-test-results/failures/expected/image-actual.checksum': 'win-image-checksum', + 'layout-test-results/failures/expected/image-actual.png': 'win-image-png', + }, + ARCHIVE_URL + '/Webkit_Win7/1/layout-test-results.zip': { + 'layout-test-results/failures/expected/image-actual.txt': 'win-image-txt', + 'layout-test-results/failures/expected/image-actual.checksum': 'win-image-checksum', + 'layout-test-results/failures/expected/image-actual.png': 'win-image-png', + }, + ARCHIVE_URL + '/Webkit_Win/1/layout-test-results.zip': { + 'layout-test-results/failures/expected/image-actual.txt': 'win-image-txt', + 'layout-test-results/failures/expected/image-actual.checksum': 'win-image-checksum', + 'layout-test-results/failures/expected/image-actual.png': 'win-image-png', + }, + ARCHIVE_URL + '/Webkit_Linux/1/layout-test-results.zip': { 'layout-test-results/failures/expected/image-actual.txt': 'win-image-txt', 'layout-test-results/failures/expected/image-actual.checksum': 'win-image-checksum', 'layout-test-results/failures/expected/image-actual.png': 'win-image-png', @@ -108,6 +131,14 @@ def test_zip_factory(): return zipfileset_mock.make_factory(ziphashes) +def test_archive(orig_archive_dict): + new_archive_dict = {} + for platform, dirname in orig_archive_dict.iteritems(): + platform = platform.replace('chromium', 'test') + new_archive_dict[platform] = dirname + return new_archive_dict + + class TestGetHostPortObject(unittest.TestCase): def assert_result(self, release_present, debug_present, valid_port_obj): # Tests whether we get a valid port object returned when we claim @@ -150,6 +181,14 @@ class TestOptions(unittest.TestCase): class TestRebaseliner(unittest.TestCase): + def setUp(self): + if not hasattr(self, '_orig_archive'): + self._orig_archive = rebaseline_chromium_webkit_tests.ARCHIVE_DIR_NAME_DICT + rebaseline_chromium_webkit_tests.ARCHIVE_DIR_NAME_DICT = test_archive(self._orig_archive) + + def tearDown(self): + rebaseline_chromium_webkit_tests.ARCHIVE_DIR_NAME_DICT = self._orig_archive + def make_rebaseliner(self, expectations): options = test_options() host_port_obj, filesystem = test_host_port_and_filesystem(options, expectations) @@ -158,11 +197,11 @@ class TestRebaseliner(unittest.TestCase): target_port_obj = port.get('test', target_options, filesystem=filesystem) target_port_obj._expectations = expectations - platform = target_port_obj.test_platform_name() + platform = target_port_obj.name() url_fetcher = test_url_fetcher(filesystem) zip_factory = test_zip_factory() - mock_scm = mocktool.MockSCM() + mock_scm = mocktool.MockSCM(filesystem) rebaseliner = rebaseline_chromium_webkit_tests.Rebaseliner(host_port_obj, target_port_obj, platform, options, url_fetcher, zip_factory, mock_scm) return rebaseliner, filesystem @@ -171,7 +210,7 @@ class TestRebaseliner(unittest.TestCase): # this method tests that was can at least instantiate an object, even # if there is nothing to do. rebaseliner, filesystem = self.make_rebaseliner("") - rebaseliner.run(False) + rebaseliner.run() self.assertEqual(len(filesystem.written_files), 1) def test_rebaselining_tests(self): @@ -179,19 +218,19 @@ class TestRebaseliner(unittest.TestCase): "BUGX REBASELINE MAC : failures/expected/image.html = IMAGE") compile_success = rebaseliner._compile_rebaselining_tests() self.assertTrue(compile_success) - self.assertEqual(set(['failures/expected/image.html']), rebaseliner.get_rebaselining_tests()) + self.assertEqual(set(['failures/expected/image.html']), rebaseliner._rebaselining_tests) def test_rebaselining_tests_should_ignore_reftests(self): rebaseliner, filesystem = self.make_rebaseliner( "BUGX REBASELINE : failures/expected/reftest.html = IMAGE") compile_success = rebaseliner._compile_rebaselining_tests() self.assertFalse(compile_success) - self.assertFalse(rebaseliner.get_rebaselining_tests()) + self.assertFalse(rebaseliner._rebaselining_tests) def test_one_platform(self): rebaseliner, filesystem = self.make_rebaseliner( "BUGX REBASELINE MAC : failures/expected/image.html = IMAGE") - rebaseliner.run(False) + rebaseliner.run() # We expect to have written 12 files over the course of this rebaseline: # *) 3 files in /__im_tmp for the extracted archive members # *) 3 new baselines under '/test.checkout/LayoutTests' @@ -201,25 +240,67 @@ class TestRebaseliner(unittest.TestCase): # create image diffs (FIXME?) and don't display the checksums. # *) 1 updated test_expectations file self.assertEqual(len(filesystem.written_files), 12) - self.assertEqual(filesystem.files['/test.checkout/LayoutTests/platform/test/test_expectations.txt'], '') - self.assertEqual(filesystem.files['/test.checkout/LayoutTests/platform/test-mac/failures/expected/image-expected.checksum'], 'new-image-checksum') - self.assertEqual(filesystem.files['/test.checkout/LayoutTests/platform/test-mac/failures/expected/image-expected.png'], 'new-image-png') - self.assertEqual(filesystem.files['/test.checkout/LayoutTests/platform/test-mac/failures/expected/image-expected.txt'], 'new-image-txt') + self.assertEqual(filesystem.files['/test.checkout/LayoutTests/platform/test-mac-leopard/failures/expected/image-expected.checksum'], 'new-image-checksum') + self.assertEqual(filesystem.files['/test.checkout/LayoutTests/platform/test-mac-leopard/failures/expected/image-expected.png'], 'new-image-png') + self.assertEqual(filesystem.files['/test.checkout/LayoutTests/platform/test-mac-leopard/failures/expected/image-expected.txt'], 'new-image-txt') def test_all_platforms(self): rebaseliner, filesystem = self.make_rebaseliner( "BUGX REBASELINE : failures/expected/image.html = IMAGE") - rebaseliner.run(False) + rebaseliner.run() # See comment in test_one_platform for an explanation of the 12 written tests. # Note that even though the rebaseline is marked for all platforms, each # rebaseliner only ever does one. self.assertEqual(len(filesystem.written_files), 12) - self.assertEqual(filesystem.files['/test.checkout/LayoutTests/platform/test/test_expectations.txt'], - 'BUGX REBASELINE WIN : failures/expected/image.html = IMAGE\n' - 'BUGX REBASELINE WIN-XP : failures/expected/image.html = IMAGE\n') - self.assertEqual(filesystem.files['/test.checkout/LayoutTests/platform/test-mac/failures/expected/image-expected.checksum'], 'new-image-checksum') - self.assertEqual(filesystem.files['/test.checkout/LayoutTests/platform/test-mac/failures/expected/image-expected.png'], 'new-image-png') - self.assertEqual(filesystem.files['/test.checkout/LayoutTests/platform/test-mac/failures/expected/image-expected.txt'], 'new-image-txt') + self.assertEqual(filesystem.files['/test.checkout/LayoutTests/platform/test-mac-leopard/failures/expected/image-expected.checksum'], 'new-image-checksum') + self.assertEqual(filesystem.files['/test.checkout/LayoutTests/platform/test-mac-leopard/failures/expected/image-expected.png'], 'new-image-png') + self.assertEqual(filesystem.files['/test.checkout/LayoutTests/platform/test-mac-leopard/failures/expected/image-expected.txt'], 'new-image-txt') + + def test_png_file_with_comment(self): + rebaseliner, filesystem = self.make_rebaseliner( + "BUGX REBASELINE MAC : failures/expected/image_checksum.html = IMAGE") + compile_success = rebaseliner._compile_rebaselining_tests() + self.assertTrue(compile_success) + self.assertEqual(set(['failures/expected/image_checksum.html']), rebaseliner._rebaselining_tests) + rebaseliner.run() + # There is one less file written than |test_one_platform| because we only + # write 2 expectations (the png and the txt file). + self.assertEqual(len(filesystem.written_files), 11) + self.assertEqual(filesystem.files['/test.checkout/LayoutTests/platform/test-mac-leopard/failures/expected/image_checksum-expected.png'], 'tEXtchecksum\x000123456789') + self.assertEqual(filesystem.files['/test.checkout/LayoutTests/platform/test-mac-leopard/failures/expected/image_checksum-expected.txt'], 'png-comment-txt') + self.assertFalse(filesystem.files.get('/test.checkout/LayoutTests/platform/test-mac-leopard/failures/expected/image_checksum-expected.checksum', None)) + + def test_png_file_with_comment_remove_old_checksum(self): + rebaseliner, filesystem = self.make_rebaseliner( + "BUGX REBASELINE MAC : failures/expected/image_checksum.html = IMAGE") + filesystem.files['/test.checkout/LayoutTests/platform/test-mac-leopard/failures/expected/image_checksum-expected.png'] = 'old' + filesystem.files['/test.checkout/LayoutTests/platform/test-mac-leopard/failures/expected/image_checksum-expected.checksum'] = 'old' + filesystem.files['/test.checkout/LayoutTests/platform/test-mac-leopard/failures/expected/image_checksum-expected.txt'] = 'old' + + compile_success = rebaseliner._compile_rebaselining_tests() + self.assertTrue(compile_success) + self.assertEqual(set(['failures/expected/image_checksum.html']), rebaseliner._rebaselining_tests) + rebaseliner.run() + # There is one more file written than |test_png_file_with_comment_remove_old_checksum| + # because we also delete the old checksum. + self.assertEqual(len(filesystem.written_files), 12) + self.assertEqual(filesystem.files['/test.checkout/LayoutTests/platform/test-mac-leopard/failures/expected/image_checksum-expected.png'], 'tEXtchecksum\x000123456789') + self.assertEqual(filesystem.files['/test.checkout/LayoutTests/platform/test-mac-leopard/failures/expected/image_checksum-expected.txt'], 'png-comment-txt') + self.assertEqual(filesystem.files.get('/test.checkout/LayoutTests/platform/test-mac-leopard/failures/expected/image_checksum-expected.checksum', None), None) + + def test_png_file_with_comment_as_duplicate(self): + rebaseliner, filesystem = self.make_rebaseliner( + "BUGX REBASELINE MAC : failures/expected/image_checksum.html = IMAGE") + filesystem.files['/test.checkout/LayoutTests/platform/test-mac-snowleopard/failures/expected/image_checksum-expected.png'] = 'tEXtchecksum\x000123456789' + filesystem.files['/test.checkout/LayoutTests/platform/test-mac-snowleopard/failures/expected/image_checksum-expected.txt'] = 'png-comment-txt' + + compile_success = rebaseliner._compile_rebaselining_tests() + self.assertTrue(compile_success) + self.assertEqual(set(['failures/expected/image_checksum.html']), rebaseliner._rebaselining_tests) + rebaseliner.run() + self.assertEqual(filesystem.files.get('/test.checkout/LayoutTests/platform/test-mac-leopard/failures/expected/image_checksum-expected.png', None), None) + self.assertEqual(filesystem.files.get('/test.checkout/LayoutTests/platform/test-mac-leopard/failures/expected/image_checksum-expected.txt', None), None) + self.assertEqual(filesystem.files.get('/test.checkout/LayoutTests/platform/test-mac-leopard/failures/expected/image_checksum-expected.checksum', None), None) def test_diff_baselines_txt(self): rebaseliner, filesystem = self.make_rebaseliner("") @@ -239,28 +320,37 @@ class TestRebaseliner(unittest.TestCase): class TestRealMain(unittest.TestCase): + def setUp(self): + if not hasattr(self, '_orig_archive'): + self._orig_archive = rebaseline_chromium_webkit_tests.ARCHIVE_DIR_NAME_DICT + rebaseline_chromium_webkit_tests.ARCHIVE_DIR_NAME_DICT = test_archive(self._orig_archive) + + def tearDown(self): + rebaseline_chromium_webkit_tests.ARCHIVE_DIR_NAME_DICT = self._orig_archive + def test_all_platforms(self): expectations = "BUGX REBASELINE : failures/expected/image.html = IMAGE" options = test_options() - host_port_obj, filesystem = test_host_port_and_filesystem(options, expectations) url_fetcher = test_url_fetcher(filesystem) zip_factory = test_zip_factory() mock_scm = mocktool.MockSCM() oc = outputcapture.OutputCapture() oc.capture_output() - rebaseline_chromium_webkit_tests.real_main(options, options, host_port_obj, - host_port_obj, url_fetcher, zip_factory, mock_scm) + res = rebaseline_chromium_webkit_tests.real_main(options, options, + host_port_obj, host_port_obj, url_fetcher, zip_factory, mock_scm) oc.restore_output() - # We expect to have written 35 files over the course of this rebaseline: - # *) 11 files * 3 ports for the new baselines and the diffs (see breakdown - # under test_one_platform, above) - # *) the updated test_expectations file - # *) the rebaseline results html file - self.assertEqual(len(filesystem.written_files), 35) - self.assertEqual(filesystem.files['/test.checkout/LayoutTests/platform/test/test_expectations.txt'], '') + # We expect to have written 36 files over the course of this rebaseline: + # *) 6*3 files in /__im_tmp/ for the archived members of the 6 ports + # *) 2*3 files in /test.checkout for actually differing baselines + # *) 1 file in /test.checkout for the updated test_expectations file + # *) 2*4 files in /tmp for the old/new baselines for the two actual ports + # *) 2 files in /tmp for the text diffs for the two ports + # *) 1 file in /tmp for the rebaseline results html file + self.assertEqual(res, 0) + self.assertEqual(len(filesystem.written_files), 36) class TestHtmlGenerator(unittest.TestCase): @@ -268,7 +358,7 @@ class TestHtmlGenerator(unittest.TestCase): options = mocktool.MockOptions(configuration=None, html_directory='/tmp') host_port = port.get('test', options, filesystem=port.unit_test_filesystem(files)) generator = rebaseline_chromium_webkit_tests.HtmlGenerator(host_port, - target_port=None, options=options, platforms=['mac'], rebaselining_tests=tests) + target_port=None, options=options, platforms=['test-mac-leopard'], rebaselining_tests=tests) return generator, host_port def test_generate_baseline_links(self): diff --git a/Tools/Scripts/webkitpy/layout_tests/run_webkit_tests.py b/Tools/Scripts/webkitpy/layout_tests/run_webkit_tests.py index d27ea1e..e814008 100755 --- a/Tools/Scripts/webkitpy/layout_tests/run_webkit_tests.py +++ b/Tools/Scripts/webkitpy/layout_tests/run_webkit_tests.py @@ -79,7 +79,7 @@ def run(port, options, args, regular_output=sys.stderr, printer.cleanup() return 0 - last_unexpected_results = _gather_unexpected_results(port._filesystem, options) + last_unexpected_results = _gather_unexpected_results(port) if options.print_last_failures: printer.write("\n".join(last_unexpected_results) + "\n") printer.cleanup() @@ -89,11 +89,7 @@ def run(port, options, args, regular_output=sys.stderr, # in a try/finally to ensure that we clean up the logging configuration. num_unexpected_results = -1 try: - if options.worker_model in ('inline', 'threads', 'processes'): - runner = test_runner2.TestRunner2(port, options, printer) - else: - runner = test_runner.TestRunner(port, options, printer) - + runner = test_runner2.TestRunner2(port, options, printer) runner._print_config() printer.print_update("Collecting tests ...") @@ -135,9 +131,9 @@ def _set_up_derived_options(port_obj, options): if options.worker_model is None: options.worker_model = port_obj.default_worker_model() - if options.worker_model in ('inline', 'old-inline'): + if options.worker_model == 'inline': if options.child_processes and int(options.child_processes) > 1: - warnings.append("--worker-model=%s overrides --child-processes" % options.worker_model) + warnings.append("--worker-model=inline overrides --child-processes") options.child_processes = "1" if not options.child_processes: options.child_processes = os.environ.get("WEBKIT_TEST_CHILD_PROCESSES", @@ -152,12 +148,6 @@ def _set_up_derived_options(port_obj, options): if not options.use_apache: options.use_apache = sys.platform in ('darwin', 'linux2') - if not port_obj._filesystem.isabs(options.results_directory): - # This normalizes the path to the build dir. - # FIXME: how this happens is not at all obvious; this is a dumb - # interface and should be cleaned up. - options.results_directory = port_obj.results_directory() - if not options.time_out_ms: if options.configuration == "Debug": options.time_out_ms = str(2 * test_runner.TestRunner.DEFAULT_TEST_TIMEOUT_MS) @@ -165,14 +155,27 @@ def _set_up_derived_options(port_obj, options): options.time_out_ms = str(test_runner.TestRunner.DEFAULT_TEST_TIMEOUT_MS) options.slow_time_out_ms = str(5 * int(options.time_out_ms)) + + if options.additional_platform_directory: + normalized_platform_directories = [] + for path in options.additional_platform_directory: + if not port_obj._filesystem.isabs(path): + warnings.append("--additional-platform-directory=%s is ignored since it is not absolute" % path) + continue + normalized_platform_directories.append(port_obj._filesystem.normpath(path)) + options.additional_platform_directory = normalized_platform_directories + return warnings -def _gather_unexpected_results(filesystem, options): +def _gather_unexpected_results(port): """Returns the unexpected results from the previous run, if any.""" + filesystem = port._filesystem + results_directory = port.results_directory() + options = port._options last_unexpected_results = [] if options.print_last_failures or options.retest_last_failures: - unexpected_results_filename = filesystem.join(options.results_directory, "unexpected_results.json") + unexpected_results_filename = filesystem.join(results_directory, "unexpected_results.json") if filesystem.exists(unexpected_results_filename): results = json_results_generator.load_json(filesystem, unexpected_results_filename) last_unexpected_results = results['tests'].keys() @@ -275,10 +278,7 @@ def parse_args(args=None): optparse.make_option("--tolerance", help="Ignore image differences less than this percentage (some " "ports may ignore this option)", type="float"), - optparse.make_option("--results-directory", - default="layout-test-results", - help="Output results directory source dir, relative to Debug or " - "Release"), + optparse.make_option("--results-directory", help="Location of test results"), optparse.make_option("--build-directory", help="Path to the directory under which build files are kept (should not include configuration)"), optparse.make_option("--new-baseline", action="store_true", @@ -288,6 +288,13 @@ def parse_args(args=None): optparse.make_option("--reset-results", action="store_true", default=False, help="Reset any existing baselines to the " "generated results"), + optparse.make_option("--additional-drt-flag", action="append", + default=[], help="Additional command line flag to pass to DumpRenderTree " + "Specify multiple times to add multiple flags."), + optparse.make_option("--additional-platform-directory", action="append", + default=[], help="Additional directory where to look for test " + "baselines (will take precendence over platform baselines). " + "Specify multiple times to add multiple search path entries."), optparse.make_option("--no-show-results", action="store_false", default=True, dest="show_results", help="Don't launch a browser with results after the tests " @@ -370,8 +377,8 @@ def parse_args(args=None): help="Number of DumpRenderTrees to run in parallel."), # FIXME: Display default number of child processes that will run. optparse.make_option("--worker-model", action="store", - default=None, help=("controls worker model. Valid values are 'old-inline', " - "'old-threads', 'inline', 'threads', and 'processes'.")), + default=None, help=("controls worker model. Valid values are " + "'inline', 'threads', and 'processes'.")), optparse.make_option("--experimental-fully-parallel", action="store_true", default=False, help="run all tests in parallel"), diff --git a/Tools/Scripts/webkitpy/layout_tests/run_webkit_tests_unittest.py b/Tools/Scripts/webkitpy/layout_tests/run_webkit_tests_unittest.py index 7076ef2..940b4b8 100644 --- a/Tools/Scripts/webkitpy/layout_tests/run_webkit_tests_unittest.py +++ b/Tools/Scripts/webkitpy/layout_tests/run_webkit_tests_unittest.py @@ -35,6 +35,7 @@ from __future__ import with_statement import codecs import itertools import logging +import os import Queue import sys import thread @@ -53,7 +54,6 @@ from webkitpy.common.system import filesystem_mock from webkitpy.tool import mocktool from webkitpy.layout_tests import port from webkitpy.layout_tests import run_webkit_tests -from webkitpy.layout_tests.layout_package import dump_render_tree_thread from webkitpy.layout_tests.port.test import TestPort, TestDriver from webkitpy.layout_tests.port.test_files import is_reference_html_file from webkitpy.python24.versioning import compare_version @@ -196,16 +196,20 @@ class MainTest(unittest.TestCase): self.assertTrue(len(batch) <= 2, '%s had too many tests' % ', '.join(batch)) def test_child_process_1(self): - (res, buildbot_output, regular_output, user) = logging_run( + _, _, regular_output, _ = logging_run( ['--print', 'config', '--worker-model', 'threads', '--child-processes', '1']) - self.assertTrue('Running one DumpRenderTree\n' - in regular_output.get()) + self.assertTrue(any(['Running 1 ' in line for line in regular_output.get()])) def test_child_processes_2(self): - (res, buildbot_output, regular_output, user) = logging_run( + _, _, regular_output, _ = logging_run( ['--print', 'config', '--worker-model', 'threads', '--child-processes', '2']) - self.assertTrue('Running 2 DumpRenderTrees in parallel\n' - in regular_output.get()) + self.assertTrue(any(['Running 2 ' in line for line in regular_output.get()])) + + def test_child_processes_min(self): + _, _, regular_output, _ = logging_run( + ['--print', 'config', '--worker-model', 'threads', '--child-processes', '2', 'passes'], + tests_included=True) + self.assertTrue(any(['Running 1 ' in line for line in regular_output.get()])) def test_dryrun(self): batch_tests_run = get_tests_run(['--dry-run']) @@ -252,8 +256,8 @@ class MainTest(unittest.TestCase): fs = port.unit_test_filesystem() # We do a logging run here instead of a passing run in order to # suppress the output from the json generator. - (res, buildbot_output, regular_output, user) = logging_run(['--clobber-old-results'], record_results=True, filesystem=fs) - (res, buildbot_output, regular_output, user) = logging_run( + res, buildbot_output, regular_output, user = logging_run(['--clobber-old-results'], record_results=True, filesystem=fs) + res, buildbot_output, regular_output, user = logging_run( ['--print-last-failures'], filesystem=fs) self.assertEqual(regular_output.get(), ['\n\n']) self.assertEqual(buildbot_output.get(), []) @@ -324,6 +328,10 @@ class MainTest(unittest.TestCase): for batch in batch_tests_run: self.assertEquals(len(batch), 1, '%s had too many tests' % ', '.join(batch)) + def test_run_singly_actually_runs_tests(self): + res, _, _, _ = logging_run(['--run-singly', 'failures/unexpected']) + self.assertEquals(res, 5) + def test_single_file(self): tests_run = get_tests_run(['passes/text.html'], tests_included=True, flatten_batches=True) self.assertEquals(['passes/text.html'], tests_run) @@ -336,6 +344,12 @@ class MainTest(unittest.TestCase): tests_run = get_tests_run(['failures/expected/keybaord.html'], tests_included=True, flatten_batches=True) self.assertEquals([], tests_run) + def test_stderr_is_saved(self): + fs = port.unit_test_filesystem() + self.assertTrue(passing_run(filesystem=fs)) + self.assertEquals(fs.read_text_file('/tmp/layout-test-results/passes/error-stderr.txt'), + 'stuff going to stderr') + def test_test_list(self): fs = port.unit_test_filesystem() filename = '/tmp/foo.txt' @@ -371,7 +385,7 @@ class MainTest(unittest.TestCase): def test_exit_after_n_failures_upload(self): fs = port.unit_test_filesystem() - (res, buildbot_output, regular_output, user) = logging_run([ + res, buildbot_output, regular_output, user = logging_run([ 'failures/unexpected/text-image-checksum.html', 'passes/text.html', '--exit-after-n-failures', '1', @@ -465,10 +479,12 @@ class MainTest(unittest.TestCase): def test_results_directory_relative(self): # We run a configuration that should fail, to generate output, then # look for what the output results url was. - + fs = port.unit_test_filesystem() + fs.maybe_make_directory('/tmp/cwd') + fs.chdir('/tmp/cwd') res, out, err, user = logging_run(['--results-directory=foo'], - tests_included=True) - self.assertEqual(user.opened_urls, ['/tmp/foo/results.html']) + tests_included=True, filesystem=fs) + self.assertEqual(user.opened_urls, ['/tmp/cwd/foo/results.html']) # These next tests test that we run the tests in ascending alphabetical # order per directory. HTTP tests are sharded separately from other tests, @@ -487,15 +503,6 @@ class MainTest(unittest.TestCase): def test_run_order__inline(self): self.assert_run_order('inline') - def test_run_order__old_inline(self): - self.assert_run_order('old-inline') - - def test_run_order__threads(self): - self.assert_run_order('old-inline', child_processes='2') - - def test_run_order__old_threads(self): - self.assert_run_order('old-threads', child_processes='2') - def test_tolerance(self): class ImageDiffTestPort(TestPort): def diff_image(self, expected_contents, actual_contents, @@ -531,12 +538,6 @@ class MainTest(unittest.TestCase): self.assertEqual(res, 0) self.assertTrue('--worker-model=inline overrides --child-processes\n' in err.get()) - def test_worker_model__old_inline(self): - self.assertTrue(passing_run(['--worker-model', 'old-inline'])) - - def test_worker_model__old_threads(self): - self.assertTrue(passing_run(['--worker-model', 'old-threads'])) - def test_worker_model__processes(self): # FIXME: remove this when we fix test-webkitpy to work properly # with the multiprocessing module (bug 54520). @@ -572,6 +573,17 @@ class MainTest(unittest.TestCase): include_reference_html=True) self.assertEquals(['passes/mismatch.html', 'passes/mismatch-expected-mismatch.html'], tests_run) + def test_additional_platform_directory(self): + self.assertTrue(passing_run(['--additional-platform-directory', '/tmp/foo'])) + self.assertTrue(passing_run(['--additional-platform-directory', '/tmp/../foo'])) + self.assertTrue(passing_run(['--additional-platform-directory', '/tmp/foo', + '--additional-platform-directory', '/tmp/bar'])) + + res, buildbot_output, regular_output, user = logging_run( + ['--additional-platform-directory', 'foo']) + self.assertTrue('--additional-platform-directory=foo is ignored since it is not absolute\n' + in regular_output.get()) + MainTest = skip_if(MainTest, sys.platform == 'cygwin' and compare_version(sys, '2.6')[0] < 0, 'new-run-webkit-tests tests hang on Cygwin Python 2.5.2') @@ -616,9 +628,9 @@ class RebaselineTest(unittest.TestCase): file_list.remove('/tmp/layout-test-results/tests_run0.txt') self.assertEqual(len(file_list), 6) self.assertBaselines(file_list, - "/platform/test-mac/passes/image") + "/platform/test-mac-leopard/passes/image") self.assertBaselines(file_list, - "/platform/test-mac/failures/expected/missing_image") + "/platform/test-mac-leopard/failures/expected/missing_image") class DryrunTest(unittest.TestCase): diff --git a/Tools/Scripts/webkitpy/style/checkers/cpp.py b/Tools/Scripts/webkitpy/style/checkers/cpp.py index 7f8a9ea..0a0db54 100644 --- a/Tools/Scripts/webkitpy/style/checkers/cpp.py +++ b/Tools/Scripts/webkitpy/style/checkers/cpp.py @@ -312,7 +312,7 @@ class _IncludeState(dict): def visited_primary_section(self): return self._visited_primary_section - def check_next_include_order(self, header_type, file_is_header): + def check_next_include_order(self, header_type, file_is_header, primary_header_exists): """Returns a non-empty error message if the next header is out of order. This function also updates the internal state to be ready to check @@ -357,7 +357,8 @@ class _IncludeState(dict): else: assert header_type == _OTHER_HEADER if not file_is_header and self._section < self._PRIMARY_SECTION: - error_message = before_error_message + if primary_header_exists: + error_message = before_error_message self._section = self._OTHER_SECTION return error_message @@ -2597,6 +2598,17 @@ def _classify_include(filename, include, is_system, include_state): return _OTHER_HEADER +def _does_primary_header_exist(filename): + """Return a primary header file name for a file, or empty string + if the file is not source file or primary header does not exist. + """ + fileinfo = FileInfo(filename) + if not fileinfo.is_source(): + return False + primary_header = fileinfo.no_extension() + ".h" + return os.path.isfile(primary_header) + + def check_include_line(filename, file_extension, clean_lines, line_number, include_state, error): """Check rules that are applicable to #include lines. @@ -2646,6 +2658,7 @@ def check_include_line(filename, file_extension, clean_lines, line_number, inclu include_state[include] = line_number header_type = _classify_include(filename, include, is_system, include_state) + primary_header_exists = _does_primary_header_exist(filename) include_state.header_types[line_number] = header_type # Only proceed if this isn't a duplicate header. @@ -2657,7 +2670,9 @@ def check_include_line(filename, file_extension, clean_lines, line_number, inclu # 2) for header files: alphabetically sorted # The include_state object keeps track of the last type seen # and complains if the header types are out of order or missing. - error_message = include_state.check_next_include_order(header_type, file_extension == "h") + error_message = include_state.check_next_include_order(header_type, + file_extension == "h", + primary_header_exists) # Check to make sure we have a blank line after primary header. if not error_message and header_type == _PRIMARY_HEADER: diff --git a/Tools/Scripts/webkitpy/style/checkers/cpp_unittest.py b/Tools/Scripts/webkitpy/style/checkers/cpp_unittest.py index 2d2abbf..a98d0dd 100644 --- a/Tools/Scripts/webkitpy/style/checkers/cpp_unittest.py +++ b/Tools/Scripts/webkitpy/style/checkers/cpp_unittest.py @@ -2452,18 +2452,20 @@ class OrderOfIncludesTest(CppStyleTestBase): # Cheat os.path.abspath called in FileInfo class. self.os_path_abspath_orig = os.path.abspath + self.os_path_isfile_orig = os.path.isfile os.path.abspath = lambda value: value def tearDown(self): os.path.abspath = self.os_path_abspath_orig + os.path.isfile = self.os_path_isfile_orig def test_check_next_include_order__no_config(self): self.assertEqual('Header file should not contain WebCore config.h.', - self.include_state.check_next_include_order(cpp_style._CONFIG_HEADER, True)) + self.include_state.check_next_include_order(cpp_style._CONFIG_HEADER, True, True)) def test_check_next_include_order__no_self(self): self.assertEqual('Header file should not contain itself.', - self.include_state.check_next_include_order(cpp_style._PRIMARY_HEADER, True)) + self.include_state.check_next_include_order(cpp_style._PRIMARY_HEADER, True, True)) # Test actual code to make sure that header types are correctly assigned. self.assert_language_rules_check('Foo.h', '#include "Foo.h"\n', @@ -2475,22 +2477,22 @@ class OrderOfIncludesTest(CppStyleTestBase): def test_check_next_include_order__likely_then_config(self): self.assertEqual('Found header this file implements before WebCore config.h.', - self.include_state.check_next_include_order(cpp_style._PRIMARY_HEADER, False)) + self.include_state.check_next_include_order(cpp_style._PRIMARY_HEADER, False, True)) self.assertEqual('Found WebCore config.h after a header this file implements.', - self.include_state.check_next_include_order(cpp_style._CONFIG_HEADER, False)) + self.include_state.check_next_include_order(cpp_style._CONFIG_HEADER, False, True)) def test_check_next_include_order__other_then_config(self): self.assertEqual('Found other header before WebCore config.h.', - self.include_state.check_next_include_order(cpp_style._OTHER_HEADER, False)) + self.include_state.check_next_include_order(cpp_style._OTHER_HEADER, False, True)) self.assertEqual('Found WebCore config.h after other header.', - self.include_state.check_next_include_order(cpp_style._CONFIG_HEADER, False)) + self.include_state.check_next_include_order(cpp_style._CONFIG_HEADER, False, True)) def test_check_next_include_order__config_then_other_then_likely(self): - self.assertEqual('', self.include_state.check_next_include_order(cpp_style._CONFIG_HEADER, False)) + self.assertEqual('', self.include_state.check_next_include_order(cpp_style._CONFIG_HEADER, False, True)) self.assertEqual('Found other header before a header this file implements.', - self.include_state.check_next_include_order(cpp_style._OTHER_HEADER, False)) + self.include_state.check_next_include_order(cpp_style._OTHER_HEADER, False, True)) self.assertEqual('Found header this file implements after other header.', - self.include_state.check_next_include_order(cpp_style._PRIMARY_HEADER, False)) + self.include_state.check_next_include_order(cpp_style._PRIMARY_HEADER, False, True)) def test_check_alphabetical_include_order(self): self.assert_language_rules_check('foo.h', @@ -2586,6 +2588,34 @@ class OrderOfIncludesTest(CppStyleTestBase): '#include "g.h"\n', '"foo.h" already included at foo.cpp:2 [build/include] [4]') + def test_primary_header(self): + # File with non-existing primary header should not produce errors. + self.assert_language_rules_check('foo.cpp', + '#include "config.h"\n' + '\n' + '#include "bar.h"\n', + '') + # Pretend that header files exist. + os.path.isfile = lambda filename: True + # Missing include for existing primary header -> error. + self.assert_language_rules_check('foo.cpp', + '#include "config.h"\n' + '\n' + '#include "bar.h"\n', + 'Found other header before a header this file implements. ' + 'Should be: config.h, primary header, blank line, and then ' + 'alphabetically sorted. [build/include_order] [4]') + # Having include for existing primary header -> no error. + self.assert_language_rules_check('foo.cpp', + '#include "config.h"\n' + '#include "foo.h"\n' + '\n' + '#include "bar.h"\n', + '') + + os.path.isfile = self.os_path_isfile_orig + + def test_check_wtf_includes(self): self.assert_language_rules_check('foo.cpp', '#include "config.h"\n' diff --git a/Tools/Scripts/webkitpy/tool/bot/botinfo.py b/Tools/Scripts/webkitpy/tool/bot/botinfo.py new file mode 100644 index 0000000..b9fd938 --- /dev/null +++ b/Tools/Scripts/webkitpy/tool/bot/botinfo.py @@ -0,0 +1,39 @@ +# Copyright (c) 2011 Google 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: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * 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. +# * Neither the name of Google Inc. 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 THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT +# OWNER OR 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. + + +# FIXME: We should consider hanging one of these off the tool object. +class BotInfo(object): + def __init__(self, tool): + self._tool = tool + + def summary_text(self): + # bot_id is also stored on the options dictionary on the tool. + bot_id = self._tool.status_server.bot_id + bot_id_string = "Bot: %s " % (bot_id) if bot_id else "" + return "%sPort: %s Platform: %s" % (bot_id_string, self._tool.port().name(), self._tool.platform.display_name()) diff --git a/Tools/Scripts/webkitpy/tool/bot/botinfo_unittest.py b/Tools/Scripts/webkitpy/tool/bot/botinfo_unittest.py new file mode 100644 index 0000000..054acfc --- /dev/null +++ b/Tools/Scripts/webkitpy/tool/bot/botinfo_unittest.py @@ -0,0 +1,40 @@ +# Copyright (c) 2011 Google 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: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * 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. +# * Neither the name of Google Inc. 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 THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT +# OWNER OR 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 unittest + +from webkitpy.tool.bot.botinfo import BotInfo +from webkitpy.tool.mocktool import MockTool, MockStatusServer + + +class BotInfoTest(unittest.TestCase): + + def test_summary_text(self): + tool = MockTool() + tool.status_server = MockStatusServer("MockBotId") + self.assertEqual(BotInfo(tool).summary_text(), "Bot: MockBotId Port: MockPort Platform: MockPlatform 1.0") diff --git a/Tools/Scripts/webkitpy/tool/bot/commitqueuetask.py b/Tools/Scripts/webkitpy/tool/bot/commitqueuetask.py index c5d9001..93cbcc8 100644 --- a/Tools/Scripts/webkitpy/tool/bot/commitqueuetask.py +++ b/Tools/Scripts/webkitpy/tool/bot/commitqueuetask.py @@ -28,6 +28,7 @@ from webkitpy.common.system.executive import ScriptError from webkitpy.common.net.layouttestresults import LayoutTestResults +from webkitpy.tool.bot.expectedfailures import ExpectedFailures class CommitQueueTaskDelegate(object): @@ -59,6 +60,8 @@ class CommitQueueTask(object): self._delegate = delegate self._patch = patch self._script_error = None + self._results_archive_from_patch_test_run = None + self._expected_failures = ExpectedFailures() def _validate(self): # Bugs might get closed, or patches might be obsoleted or r-'d while the @@ -132,7 +135,7 @@ class CommitQueueTask(object): "Unable to build without patch") def _test(self): - return self._run_command([ + success = self._run_command([ "build-and-test", "--no-clean", "--no-update", @@ -143,8 +146,11 @@ class CommitQueueTask(object): "Passed tests", "Patch does not pass tests") + self._expected_failures.shrink_expected_failures(self._delegate.layout_test_results(), success) + return success + def _build_and_test_without_patch(self): - return self._run_command([ + success = self._run_command([ "build-and-test", "--force-clean", "--no-update", @@ -155,11 +161,8 @@ class CommitQueueTask(object): "Able to pass tests without patch", "Unable to pass tests without patch (tree is red?)") - def _failing_results_from_last_run(self): - results = self._delegate.layout_test_results() - if not results: - return [] # Makes callers slighty cleaner to not have to deal with None - return results.failing_test_results() + self._expected_failures.shrink_expected_failures(self._delegate.layout_test_results(), success) + return success def _land(self): # Unclear if this should pass --quiet or not. If --parent-command always does the reporting, then it should. @@ -177,36 +180,59 @@ class CommitQueueTask(object): def _report_flaky_tests(self, flaky_test_results, results_archive): self._delegate.report_flaky_tests(self._patch, flaky_test_results, results_archive) + def _results_failed_different_tests(self, first, second): + first_failing_tests = [] if not first else first.failing_tests() + second_failing_tests = [] if not second else second.failing_tests() + return first_failing_tests != second_failing_tests + def _test_patch(self): if self._test(): return True - first_results = self._failing_results_from_last_run() - first_failing_tests = [result.filename for result in first_results] + # Note: archive_last_layout_test_results deletes the results directory, making these calls order-sensitve. + # We could remove this dependency by building the layout_test_results from the archive. + first_results = self._delegate.layout_test_results() first_results_archive = self._delegate.archive_last_layout_test_results(self._patch) + + if self._expected_failures.failures_were_expected(first_results): + return True + if self._test(): - # Only report flaky tests if we were successful at archiving results. - if first_results_archive: - self._report_flaky_tests(first_results, first_results_archive) + # Only report flaky tests if we were successful at parsing results.html and archiving results. + if first_results and first_results_archive: + self._report_flaky_tests(first_results.failing_test_results(), first_results_archive) return True - second_results = self._failing_results_from_last_run() - second_failing_tests = [result.filename for result in second_results] - if first_failing_tests != second_failing_tests: - # We could report flaky tests here, but since run-webkit-tests - # is run with --exit-after-N-failures=1, we would need to - # be careful not to report constant failures as flaky due to earlier - # flaky test making them not fail (no results) in one of the runs. + second_results = self._delegate.layout_test_results() + if self._results_failed_different_tests(first_results, second_results): + # We could report flaky tests here, but we would need to be careful + # to use similar checks to ExpectedFailures._can_trust_results + # to make sure we don't report constant failures as flakes when + # we happen to hit the --exit-after-N-failures limit. # See https://bugs.webkit.org/show_bug.cgi?id=51272 return False + # Archive (and remove) second results so layout_test_results() after + # build_and_test_without_patch won't use second results instead of the clean-tree results. + second_results_archive = self._delegate.archive_last_layout_test_results(self._patch) + if self._build_and_test_without_patch(): - return self.report_failure() # The error from the previous ._test() run is real, report it. - return False # Tree must be red, just retry later. + # The error from the previous ._test() run is real, report it. + return self.report_failure(first_results_archive) + + clean_tree_results = self._delegate.layout_test_results() + self._expected_failures.grow_expected_failures(clean_tree_results) + + return False # Tree must be redder than we expected, just retry later. + + def results_archive_from_patch_test_run(self, patch): + assert(self._patch.id() == patch.id()) # CommitQueueTask is not currently re-useable. + return self._results_archive_from_patch_test_run - def report_failure(self): + def report_failure(self, results_archive=None): if not self._validate(): return False + self._results_archive_from_patch_test_run = results_archive raise self._script_error def run(self): diff --git a/Tools/Scripts/webkitpy/tool/bot/commitqueuetask_unittest.py b/Tools/Scripts/webkitpy/tool/bot/commitqueuetask_unittest.py index 87d0ab5..7324d78 100644 --- a/Tools/Scripts/webkitpy/tool/bot/commitqueuetask_unittest.py +++ b/Tools/Scripts/webkitpy/tool/bot/commitqueuetask_unittest.py @@ -30,6 +30,7 @@ from datetime import datetime import unittest from webkitpy.common.net import bugzilla +from webkitpy.common.net.layouttestresults import LayoutTestResults from webkitpy.common.system.deprecated_logging import error, log from webkitpy.common.system.outputcapture import OutputCapture from webkitpy.layout_tests.layout_package import test_results @@ -77,9 +78,6 @@ class MockCommitQueue(CommitQueueTaskDelegate): class CommitQueueTaskTest(unittest.TestCase): - def _mock_test_result(self, testname): - return test_results.TestResult(testname, [test_failures.FailureTextMismatch()]) - def _run_through_task(self, commit_queue, expected_stderr, expected_exception=None, expect_retry=False): tool = MockTool(log_executive=True) patch = tool.bugs.fetch_attachment(197) @@ -190,6 +188,9 @@ command_failed: failure_message='Unable to build without patch' script_error='MO None, ScriptError("MOCK tests failure"), ]) + # CommitQueueTask will only report flaky tests if we successfully parsed + # results.html and returned a LayoutTestResults object, so we fake one. + commit_queue.layout_test_results = lambda: LayoutTestResults([]) expected_stderr = """run_webkit_patch: ['clean'] command_passed: success_message='Cleaned working directory' patch='197' run_webkit_patch: ['update'] @@ -217,6 +218,7 @@ command_passed: success_message='Landed patch' patch='197' None, ScriptError("MOCK tests failure"), ]) + commit_queue.layout_test_results = lambda: LayoutTestResults([]) # It's possible delegate to fail to archive layout tests, don't try to report # flaky tests when that happens. commit_queue.archive_last_layout_test_results = lambda patch: None @@ -237,10 +239,25 @@ command_passed: success_message='Landed patch' patch='197' """ self._run_through_task(commit_queue, expected_stderr) - _double_flaky_test_counter = 0 - def test_double_flaky_test_failure(self): - commit_queue = MockCommitQueue([ + class DoubleFlakyCommitQueue(MockCommitQueue): + def __init__(self, error_plan): + MockCommitQueue.__init__(self, error_plan) + self._double_flaky_test_counter = 0 + + def run_command(self, command): + self._double_flaky_test_counter += 1 + MockCommitQueue.run_command(self, command) + + def _mock_test_result(self, testname): + return test_results.TestResult(testname, [test_failures.FailureTextMismatch()]) + + def layout_test_results(self): + if self._double_flaky_test_counter % 2: + return LayoutTestResults([self._mock_test_result('foo.html')]) + return LayoutTestResults([self._mock_test_result('bar.html')]) + + commit_queue = DoubleFlakyCommitQueue([ None, None, None, @@ -268,15 +285,6 @@ command_failed: failure_message='Patch does not pass tests' script_error='MOCK t tool = MockTool(log_executive=True) patch = tool.bugs.fetch_attachment(197) task = CommitQueueTask(commit_queue, patch) - self._double_flaky_test_counter = 0 - - def mock_failing_results_from_last_run(): - CommitQueueTaskTest._double_flaky_test_counter += 1 - if CommitQueueTaskTest._double_flaky_test_counter % 2: - return [self._mock_test_result('foo.html')] - return [self._mock_test_result('bar.html')] - - task._failing_results_from_last_run = mock_failing_results_from_last_run success = OutputCapture().assert_outputs(self, task.run, expected_stderr=expected_stderr) self.assertEqual(success, False) @@ -302,6 +310,7 @@ command_failed: failure_message='Patch does not pass tests' script_error='MOCK t archive_last_layout_test_results: patch='197' run_webkit_patch: ['build-and-test', '--no-clean', '--no-update', '--test', '--non-interactive'] command_failed: failure_message='Patch does not pass tests' script_error='MOCK test failure again' patch='197' +archive_last_layout_test_results: patch='197' run_webkit_patch: ['build-and-test', '--force-clean', '--no-update', '--build', '--test', '--non-interactive'] command_passed: success_message='Able to pass tests without patch' patch='197' """ @@ -330,6 +339,7 @@ command_failed: failure_message='Patch does not pass tests' script_error='MOCK t archive_last_layout_test_results: patch='197' run_webkit_patch: ['build-and-test', '--no-clean', '--no-update', '--test', '--non-interactive'] command_failed: failure_message='Patch does not pass tests' script_error='MOCK test failure again' patch='197' +archive_last_layout_test_results: patch='197' run_webkit_patch: ['build-and-test', '--force-clean', '--no-update', '--build', '--test', '--non-interactive'] command_failed: failure_message='Unable to pass tests without patch (tree is red?)' script_error='MOCK clean test failure' patch='197' """ diff --git a/Tools/Scripts/webkitpy/tool/bot/expectedfailures.py b/Tools/Scripts/webkitpy/tool/bot/expectedfailures.py new file mode 100644 index 0000000..8736ac0 --- /dev/null +++ b/Tools/Scripts/webkitpy/tool/bot/expectedfailures.py @@ -0,0 +1,55 @@ +# Copyright (c) 2011 Google 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: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * 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. +# * Neither the name of Google Inc. 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 THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT +# OWNER OR 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. + + +class ExpectedFailures(object): + def __init__(self): + self._failures = set() + + def _can_trust_results(self, results): + if not results or not results.failure_limit_count(): + return False + return len(results.failing_tests()) != 0 and len(results.failing_tests()) != results.failure_limit_count() + + def failures_were_expected(self, results): + if not self._can_trust_results(results): + return False + return set(results.failing_tests()) <= self._failures + + def shrink_expected_failures(self, results, run_success): + if run_success: + self._failures = set() + elif self._can_trust_results(results): + # Remove all expected failures which are not in the new failing results. + self._failures.intersection_update(set(results.failing_tests())) + + def grow_expected_failures(self, results): + if not self._can_trust_results(results): + return + self._failures.update(results.failing_tests()) + # FIXME: Should we assert() here that expected_failures never crosses a certain size? diff --git a/Tools/Scripts/webkitpy/tool/bot/expectedfailures_unittest.py b/Tools/Scripts/webkitpy/tool/bot/expectedfailures_unittest.py new file mode 100644 index 0000000..8a2702b --- /dev/null +++ b/Tools/Scripts/webkitpy/tool/bot/expectedfailures_unittest.py @@ -0,0 +1,73 @@ +# Copyright (c) 2009 Google 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: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * 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. +# * Neither the name of Google Inc. 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 THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT +# OWNER OR 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 unittest + +from webkitpy.tool.bot.expectedfailures import ExpectedFailures + + +class MockResults(object): + def __init__(self, failing_tests=[], failure_limit=10): + self._failing_tests = failing_tests + self._failure_limit_count = failure_limit + + def failure_limit_count(self): + return self._failure_limit_count + + def failing_tests(self): + return self._failing_tests + + +class ExpectedFailuresTest(unittest.TestCase): + def _assert_can_trust(self, results, can_trust): + self.assertEquals(ExpectedFailures()._can_trust_results(results), can_trust) + + def test_can_trust_results(self): + self._assert_can_trust(None, False) + self._assert_can_trust(MockResults(failing_tests=[], failure_limit=None), False) + self._assert_can_trust(MockResults(failing_tests=[], failure_limit=10), False) + self._assert_can_trust(MockResults(failing_tests=[1], failure_limit=None), False) + self._assert_can_trust(MockResults(failing_tests=[1], failure_limit=2), True) + self._assert_can_trust(MockResults(failing_tests=[1], failure_limit=1), False) + + def _assert_expected(self, expected_failures, failures, expected): + self.assertEqual(expected_failures.failures_were_expected(MockResults(failures)), expected) + + def test_failures_were_expected(self): + failures = ExpectedFailures() + failures.grow_expected_failures(MockResults(['foo.html'])) + self._assert_expected(failures, ['foo.html'], True) + self._assert_expected(failures, ['bar.html'], False) + failures.shrink_expected_failures(MockResults(['baz.html']), False) + self._assert_expected(failures, ['foo.html'], False) + self._assert_expected(failures, ['baz.html'], False) + + failures.grow_expected_failures(MockResults(['baz.html'])) + self._assert_expected(failures, ['baz.html'], True) + failures.shrink_expected_failures(MockResults(), True) + self._assert_expected(failures, ['baz.html'], False) diff --git a/Tools/Scripts/webkitpy/tool/bot/flakytestreporter.py b/Tools/Scripts/webkitpy/tool/bot/flakytestreporter.py index bec593b..68e1c94 100644 --- a/Tools/Scripts/webkitpy/tool/bot/flakytestreporter.py +++ b/Tools/Scripts/webkitpy/tool/bot/flakytestreporter.py @@ -33,6 +33,7 @@ import os.path from webkitpy.common.net.layouttestresults import path_for_layout_test, LayoutTestResults from webkitpy.common.config import urls +from webkitpy.tool.bot.botinfo import BotInfo from webkitpy.tool.grammar import plural, pluralize, join_with_separators _log = logging.getLogger(__name__) @@ -42,6 +43,7 @@ class FlakyTestReporter(object): def __init__(self, tool, bot_name): self._tool = tool self._bot_name = bot_name + self._bot_info = BotInfo(tool) def _author_emails_for_test(self, flaky_test): test_path = path_for_layout_test(flaky_test) @@ -121,15 +123,10 @@ If you would like to track this test fix with another bug, please close this bug authors_string = join_with_separators(sorted(author_emails)) return " (%s: %s)" % (heading_string, authors_string) - def _bot_information(self): - bot_id = self._tool.status_server.bot_id - bot_id_string = "Bot: %s " % (bot_id) if bot_id else "" - return "%sPort: %s Platform: %s" % (bot_id_string, self._tool.port().name(), self._tool.platform.display_name()) - def _latest_flake_message(self, flaky_result, patch): failure_messages = [failure.message() for failure in flaky_result.failures] flake_message = "The %s just saw %s flake (%s) while processing attachment %s on bug %s." % (self._bot_name, flaky_result.filename, ", ".join(failure_messages), patch.id(), patch.bug_id()) - return "%s\n%s" % (flake_message, self._bot_information()) + return "%s\n%s" % (flake_message, self._bot_info.summary_text()) def _results_diff_path_for_test(self, test_path): # FIXME: This is a big hack. We should get this path from results.json diff --git a/Tools/Scripts/webkitpy/tool/bot/flakytestreporter_unittest.py b/Tools/Scripts/webkitpy/tool/bot/flakytestreporter_unittest.py index 26c98c1..1e3f35a 100644 --- a/Tools/Scripts/webkitpy/tool/bot/flakytestreporter_unittest.py +++ b/Tools/Scripts/webkitpy/tool/bot/flakytestreporter_unittest.py @@ -97,12 +97,6 @@ blocked: 50856 bug = tool.bugs.fetch_bug(78) self.assertEqual(reporter._follow_duplicate_chain(bug).id(), 76) - def test_bot_information(self): - tool = MockTool() - tool.status_server = MockStatusServer("MockBotId") - reporter = FlakyTestReporter(tool, 'dummy-queue') - self.assertEqual(reporter._bot_information(), "Bot: MockBotId Port: MockPort Platform: MockPlatform 1.0") - def test_report_flaky_tests_creating_bug(self): tool = MockTool() tool.filesystem = MockFileSystem({"/mock/foo/bar-diffs.txt": "mock"}) diff --git a/Tools/Scripts/webkitpy/tool/commands/download_unittest.py b/Tools/Scripts/webkitpy/tool/commands/download_unittest.py index ced5b2f..c8e5fd6 100644 --- a/Tools/Scripts/webkitpy/tool/commands/download_unittest.py +++ b/Tools/Scripts/webkitpy/tool/commands/download_unittest.py @@ -123,8 +123,13 @@ class DownloadCommandsTest(CommandsTest): self.assert_execute_outputs(Land(), [42], options=self._default_options(), expected_stderr=expected_stderr, tool=mock_tool) def test_check_style(self): - expected_stderr = "Processing 1 patch from 1 bug.\nUpdating working directory\nProcessing patch 197 from bug 42.\nRunning check-webkit-style\n" - self.assert_execute_outputs(CheckStyle(), [197], options=self._default_options(), expected_stderr=expected_stderr) + expected_stderr = """Processing 1 patch from 1 bug. +Updating working directory +MOCK run_and_throw_if_fail: ['mock-update-webkit'] +Processing patch 197 from bug 42. +MOCK run_and_throw_if_fail: ['mock-check-webkit-style', '--git-commit', 'MOCK git commit', '--diff-files', 'MockFile1'] +""" + self.assert_execute_outputs(CheckStyle(), [197], options=self._default_options(), expected_stderr=expected_stderr, tool=MockTool(log_executive=True)) def test_build_attachment(self): expected_stderr = "Processing 1 patch from 1 bug.\nUpdating working directory\nProcessing patch 197 from bug 42.\nBuilding WebKit\n" @@ -171,7 +176,7 @@ Not closing bug 42 as attachment 197 has review=+. Assuming there are more patc self.assert_execute_outputs(LandFromBug(), [42], options=self._default_options(), expected_stderr=expected_stderr) def test_prepare_rollout(self): - expected_stderr = "Preparing rollout for bug 42.\nUpdating working directory\nRunning prepare-ChangeLog\n" + expected_stderr = "Preparing rollout for bug 42.\nUpdating working directory\n" self.assert_execute_outputs(PrepareRollout(), [852, "Reason"], options=self._default_options(), expected_stderr=expected_stderr) def test_create_rollout(self): @@ -184,7 +189,6 @@ Reason component: MOCK component cc: MOCK cc blocked: 42 -Running prepare-ChangeLog MOCK add_patch_to_bug: bug_id=78, description=ROLLOUT of r852, mark_for_review=False, mark_for_commit_queue=True, mark_for_landing=False -- Begin comment -- Any committer can land this patch automatically by marking it commit-queue+. The commit-queue will build and test the patch before landing to ensure that the rollout will be successful. This process takes approximately 15 minutes. @@ -202,7 +206,6 @@ where ATTACHMENT_ID is the ID of this attachment. def test_rollout(self): expected_stderr = """Preparing rollout for bug 42. Updating working directory -Running prepare-ChangeLog MOCK: user.open_url: file://... Was that diff correct? Building WebKit diff --git a/Tools/Scripts/webkitpy/tool/commands/queues.py b/Tools/Scripts/webkitpy/tool/commands/queues.py index 9e50dd4..4eadb0e 100644 --- a/Tools/Scripts/webkitpy/tool/commands/queues.py +++ b/Tools/Scripts/webkitpy/tool/commands/queues.py @@ -44,11 +44,13 @@ from webkitpy.common.net.layouttestresults import LayoutTestResults from webkitpy.common.net.statusserver import StatusServer from webkitpy.common.system.deprecated_logging import error, log from webkitpy.common.system.executive import ScriptError +from webkitpy.tool.bot.botinfo import BotInfo from webkitpy.tool.bot.commitqueuetask import CommitQueueTask, CommitQueueTaskDelegate from webkitpy.tool.bot.feeders import CommitQueueFeeder, EWSFeeder from webkitpy.tool.bot.queueengine import QueueEngine, QueueEngineDelegate from webkitpy.tool.bot.flakytestreporter import FlakyTestReporter from webkitpy.tool.commands.stepsequence import StepSequenceErrorHandler +from webkitpy.tool.steps.runtests import RunTests from webkitpy.tool.multicommandtool import Command, TryAgain @@ -258,6 +260,20 @@ class CommitQueue(AbstractPatchQueue, StepSequenceErrorHandler, CommitQueueTaskD self._update_status("Processing %s" % patch_text, patch) return True + # FIXME: This is not really specific to the commit-queue and could be shared. + def _upload_results_archive_for_patch(self, patch, results_archive_zip): + bot_id = self._tool.status_server.bot_id or "bot" + description = "Archive of layout-test-results from %s" % bot_id + # results_archive is a ZipFile object, grab the File object (.fp) to pass to Mechanize for uploading. + results_archive_file = results_archive_zip.fp + # Rewind the file object to start (since Mechanize won't do that automatically) + # See https://bugs.webkit.org/show_bug.cgi?id=54593 + results_archive_file.seek(0) + comment_text = "The attached test failures were seen while running run-webkit-tests on the %s.\n" % (self.name) + # FIXME: We could easily list the test failures from the archive here. + comment_text += BotInfo(self._tool).summary_text() + self._tool.bugs.add_attachment_to_bug(patch.bug_id(), results_archive_file, description, filename="layout-test-results.zip", comment_text=comment_text) + def process_work_item(self, patch): self._cc_watchers(patch.bug_id()) task = CommitQueueTask(self, patch) @@ -269,6 +285,9 @@ class CommitQueue(AbstractPatchQueue, StepSequenceErrorHandler, CommitQueueTaskD except ScriptError, e: validator = CommitterValidator(self._tool.bugs) validator.reject_patch_from_commit_queue(patch.id(), self._error_message_for_bug(task.failure_status_id, e)) + results_archive = task.results_archive_from_patch_test_run(patch) + if results_archive: + self._upload_results_archive_for_patch(patch, results_archive) self._did_fail(patch) def _error_message_for_bug(self, status_id, script_error): @@ -296,19 +315,28 @@ class CommitQueue(AbstractPatchQueue, StepSequenceErrorHandler, CommitQueueTaskD # tool.filesystem.read_text_file. They have different error handling at the moment. def _read_file_contents(self, path): try: - with codecs.open(path, "r", "utf-8") as open_file: - return open_file.read() - except OSError, e: # File does not exist or can't be read. + return self._tool.filesystem.read_text_file(path) + except IOError, e: # File does not exist or can't be read. return None - # FIXME: This may belong on the Port object. - def layout_test_results(self): + # FIXME: This logic should move to the port object. + def _create_layout_test_results(self): results_path = self._tool.port().layout_tests_results_path() results_html = self._read_file_contents(results_path) if not results_html: return None return LayoutTestResults.results_from_string(results_html) + def layout_test_results(self): + results = self._create_layout_test_results() + # FIXME: We should not have to set failure_limit_count, but we + # do until run-webkit-tests can be updated save off the value + # of --exit-after-N-failures in results.html/results.json. + # https://bugs.webkit.org/show_bug.cgi?id=58481 + if results: + results.set_failure_limit_count(RunTests.NON_INTERACTIVE_FAILURE_LIMIT_COUNT) + return results + def _results_directory(self): results_path = self._tool.port().layout_tests_results_path() # FIXME: This is wrong in two ways: diff --git a/Tools/Scripts/webkitpy/tool/commands/queues_unittest.py b/Tools/Scripts/webkitpy/tool/commands/queues_unittest.py index e2fb09f..d577baa 100644 --- a/Tools/Scripts/webkitpy/tool/commands/queues_unittest.py +++ b/Tools/Scripts/webkitpy/tool/commands/queues_unittest.py @@ -253,6 +253,7 @@ MOCK: release_work_item: commit-queue 197 def test_rollout(self): tool = MockTool(log_executive=True) + tool.filesystem.write_text_file('/mock/results.html', '') # Otherwise the commit-queue will hit a KeyError trying to read the results from the MockFileSystem. tool.buildbot.light_tree_on_fire() expected_stderr = { "begin_work_queue": self._default_begin_work_queue_stderr("commit-queue", MockSCM.fake_checkout_root), @@ -321,6 +322,7 @@ MOCK: release_work_item: commit-queue 106 def test_manual_reject_during_processing(self): queue = SecondThoughtsCommitQueue() queue.bind_to_tool(MockTool()) + queue._tool.filesystem.write_text_file('/mock/results.html', '') # Otherwise the commit-queue will hit a KeyError trying to read the results from the MockFileSystem. queue._options = Mock() queue._options.port = None expected_stderr = """MOCK: update_status: commit-queue Cleaned working directory @@ -376,6 +378,17 @@ The commit-queue is continuing to process your patch. OutputCapture().assert_outputs(self, queue.report_flaky_tests, [QueuesTest.mock_work_item, test_results, MockZipFile()], expected_stderr=expected_stderr) + def test_missing_layout_test_results(self): + queue = CommitQueue() + tool = MockTool() + results_path = '/mock/results.html' + tool.filesystem = MockFileSystem({results_path: None}) + queue.bind_to_tool(tool) + # Make sure that our filesystem mock functions as we expect. + self.assertRaises(IOError, tool.filesystem.read_text_file, results_path) + # layout_test_results shouldn't raise even if the results.html file is missing. + self.assertEquals(queue.layout_test_results(), None) + def test_layout_test_results(self): queue = CommitQueue() queue.bind_to_tool(MockTool()) @@ -383,13 +396,30 @@ The commit-queue is continuing to process your patch. self.assertEquals(queue.layout_test_results(), None) queue._read_file_contents = lambda path: "" self.assertEquals(queue.layout_test_results(), None) + queue._create_layout_test_results = lambda: LayoutTestResults([]) + results = queue.layout_test_results() + self.assertNotEquals(results, None) + self.assertEquals(results.failure_limit_count(), 10) # This value matches RunTests.NON_INTERACTIVE_FAILURE_LIMIT_COUNT def test_archive_last_layout_test_results(self): queue = CommitQueue() queue.bind_to_tool(MockTool()) patch = queue._tool.bugs.fetch_attachment(128) + # This is just to test that the method doesn't raise. queue.archive_last_layout_test_results(patch) + def test_upload_results_archive_for_patch(self): + queue = CommitQueue() + queue.bind_to_tool(MockTool()) + patch = queue._tool.bugs.fetch_attachment(128) + expected_stderr = """MOCK add_attachment_to_bug: bug_id=42, description=Archive of layout-test-results from bot filename=layout-test-results.zip +-- Begin comment -- +The attached test failures were seen while running run-webkit-tests on the commit-queue. +Port: MockPort Platform: MockPlatform 1.0 +-- End comment -- +""" + OutputCapture().assert_outputs(self, queue._upload_results_archive_for_patch, [patch, Mock()], expected_stderr=expected_stderr) + class StyleQueueTest(QueuesTest): def test_style_queue(self): diff --git a/Tools/Scripts/webkitpy/tool/commands/queuestest.py b/Tools/Scripts/webkitpy/tool/commands/queuestest.py index 6455617..758832e 100644 --- a/Tools/Scripts/webkitpy/tool/commands/queuestest.py +++ b/Tools/Scripts/webkitpy/tool/commands/queuestest.py @@ -67,6 +67,9 @@ class QueuesTest(unittest.TestCase): def assert_queue_outputs(self, queue, args=None, work_item=None, expected_stdout=None, expected_stderr=None, expected_exceptions=None, options=None, tool=None): if not tool: tool = MockTool() + # This is a hack to make it easy for callers to not have to setup a custom MockFileSystem just to test the commit-queue + # the cq tries to read the layout test results, and will hit a KeyError in MockFileSystem if we don't do this. + tool.filesystem.write_text_file('/mock/results.html', "") if not expected_stdout: expected_stdout = {} if not expected_stderr: diff --git a/Tools/Scripts/webkitpy/tool/commands/roll_unittest.py b/Tools/Scripts/webkitpy/tool/commands/roll_unittest.py index b6f69ea..da5c635 100644 --- a/Tools/Scripts/webkitpy/tool/commands/roll_unittest.py +++ b/Tools/Scripts/webkitpy/tool/commands/roll_unittest.py @@ -36,7 +36,6 @@ class RollCommandsTest(CommandsTest): def test_update_chromium_deps(self): expected_stderr = """Updating Chromium DEPS to 6764 MOCK: MockDEPS.write_variable(chromium_rev, 6764) -Running prepare-ChangeLog MOCK: user.open_url: file://... Was that diff correct? Committed r49824: <http://trac.webkit.org/changeset/49824> diff --git a/Tools/Scripts/webkitpy/tool/commands/upload_unittest.py b/Tools/Scripts/webkitpy/tool/commands/upload_unittest.py index 4313df9..4870423 100644 --- a/Tools/Scripts/webkitpy/tool/commands/upload_unittest.py +++ b/Tools/Scripts/webkitpy/tool/commands/upload_unittest.py @@ -59,8 +59,7 @@ class UploadCommandsTest(CommandsTest): options.request_commit = False options.review = True options.suggest_reviewers = False - expected_stderr = """Running check-webkit-style -MOCK: user.open_url: file://... + expected_stderr = """MOCK: user.open_url: file://... Was that diff correct? Obsoleting 2 old patches on bug 42 MOCK add_patch_to_bug: bug_id=42, description=MOCK description, mark_for_review=True, mark_for_commit_queue=False, mark_for_landing=False @@ -107,8 +106,7 @@ extra comment options.request_commit = False options.review = True options.suggest_reviewers = False - expected_stderr = """Running check-webkit-style -MOCK: user.open_url: file://... + expected_stderr = """MOCK: user.open_url: file://... Was that diff correct? Obsoleting 2 old patches on bug 42 MOCK add_patch_to_bug: bug_id=42, description=MOCK description, mark_for_review=True, mark_for_commit_queue=False, mark_for_landing=False diff --git a/Tools/Scripts/webkitpy/tool/mocktool.py b/Tools/Scripts/webkitpy/tool/mocktool.py index 73f55a7..ad03244 100644 --- a/Tools/Scripts/webkitpy/tool/mocktool.py +++ b/Tools/Scripts/webkitpy/tool/mocktool.py @@ -458,13 +458,14 @@ class MockSCM(Mock): fake_checkout_root = os.path.realpath("/tmp") # realpath is needed to allow for Mac OS X's /private/tmp - def __init__(self): + def __init__(self, filesystem=None): Mock.__init__(self) # FIXME: We should probably use real checkout-root detection logic here. # os.getcwd() can't work here because other parts of the code assume that "checkout_root" # will actually be the root. Since getcwd() is wrong, use a globally fake root for now. self.checkout_root = self.fake_checkout_root self.added_paths = set() + self._filesystem = filesystem def add(self, destination_path, return_exit_code=False): self.added_paths.add(destination_path) @@ -502,6 +503,12 @@ class MockSCM(Mock): def svn_revision_from_commit_text(self, commit_text): return "49824" + def delete(self, path): + if not self._filesystem: + return + if self._filesystem.exists(path): + self._filesystem.remove(path) + class MockDEPS(object): def read_variable(self, name): @@ -686,6 +693,13 @@ class MockPort(Mock): def layout_tests_results_path(self): return "/mock/results.html" + def check_webkit_style_command(self): + return ["mock-check-webkit-style"] + + def update_webkit_command(self): + return ["mock-update-webkit"] + + class MockTestPort1(object): def skips_layout_test(self, test_name): diff --git a/Tools/Scripts/webkitpy/tool/steps/abstractstep.py b/Tools/Scripts/webkitpy/tool/steps/abstractstep.py index 2ba4291..59ea36a 100644 --- a/Tools/Scripts/webkitpy/tool/steps/abstractstep.py +++ b/Tools/Scripts/webkitpy/tool/steps/abstractstep.py @@ -26,7 +26,6 @@ # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -from webkitpy.common.system.deprecated_logging import log from webkitpy.common.system.executive import ScriptError from webkitpy.common.config.ports import WebKitPort from webkitpy.tool.steps.options import Options @@ -37,14 +36,6 @@ class AbstractStep(object): self._tool = tool self._options = options - # FIXME: This should use tool.port() - def _run_script(self, script_name, args=None, quiet=False, port=WebKitPort): - log("Running %s" % script_name) - command = port.script_shell_command(script_name) - if args: - command.extend(args) - self._tool.executive.run_and_throw_if_fail(command, quiet) - def _changed_files(self, state): return self.cached_lookup(state, "changed_files") diff --git a/Tools/Scripts/webkitpy/tool/steps/checkstyle.py b/Tools/Scripts/webkitpy/tool/steps/checkstyle.py index af66c50..c2377e9 100644 --- a/Tools/Scripts/webkitpy/tool/steps/checkstyle.py +++ b/Tools/Scripts/webkitpy/tool/steps/checkstyle.py @@ -56,7 +56,7 @@ class CheckStyle(AbstractStep): args.extend(self._changed_files(state)) try: - self._run_script("check-webkit-style", args) + self._tool.executive.run_and_throw_if_fail(self._tool.port().check_webkit_style_command() + args) except ScriptError, e: if self._options.non_interactive: # We need to re-raise the exception here to have the diff --git a/Tools/Scripts/webkitpy/tool/steps/commit.py b/Tools/Scripts/webkitpy/tool/steps/commit.py index 5dc4efb..7a03528 100644 --- a/Tools/Scripts/webkitpy/tool/steps/commit.py +++ b/Tools/Scripts/webkitpy/tool/steps/commit.py @@ -50,6 +50,7 @@ class Commit(AbstractStep): self._state = state username = None + password = None force_squash = False num_tries = 0 @@ -58,7 +59,7 @@ class Commit(AbstractStep): try: scm = self._tool.scm() - commit_text = scm.commit_with_message(self._commit_message, git_commit=self._options.git_commit, username=username, force_squash=force_squash, changed_files=self._changed_files(state)) + commit_text = scm.commit_with_message(self._commit_message, git_commit=self._options.git_commit, username=username, password=password, force_squash=force_squash, changed_files=self._changed_files(state)) svn_revision = scm.svn_revision_from_commit_text(commit_text) log("Committed r%s: <%s>" % (svn_revision, urls.view_revision_url(svn_revision))) self._state["commit_text"] = commit_text @@ -72,4 +73,8 @@ class Commit(AbstractStep): except AuthenticationError, e: username = self._tool.user.prompt("%s login: " % e.server_host, repeat=5) if not username: - raise ScriptError("You need to specify the username on %s to perform the commit as." % self.svn_server_host) + raise ScriptError("You need to specify the username on %s to perform the commit as." % e.server_host) + if e.prompt_for_password: + password = self._tool.user.prompt_password("%s password for %s: " % (e.server_host, username), repeat=5) + if not password: + raise ScriptError("You need to specify the password for %s on %s to perform the commit." % (username, e.server_host)) diff --git a/Tools/Scripts/webkitpy/tool/steps/preparechangelog.py b/Tools/Scripts/webkitpy/tool/steps/preparechangelog.py index 4be40ca..b30dd2f 100644 --- a/Tools/Scripts/webkitpy/tool/steps/preparechangelog.py +++ b/Tools/Scripts/webkitpy/tool/steps/preparechangelog.py @@ -61,7 +61,7 @@ class PrepareChangeLog(AbstractStep): self._ensure_bug_url(state) return os.chdir(self._tool.scm().checkout_root) - args = self._tool.port().script_shell_command("prepare-ChangeLog") + args = self._tool.port().prepare_changelog_command() if state.get("bug_id"): args.append("--bug=%s" % state["bug_id"]) args.append("--description=%s" % self._tool.bugs.fetch_bug(state["bug_id"]).title()) diff --git a/Tools/Scripts/webkitpy/tool/steps/preparechangelogfordepsroll.py b/Tools/Scripts/webkitpy/tool/steps/preparechangelogfordepsroll.py index 39c9a9a..e636cb4 100644 --- a/Tools/Scripts/webkitpy/tool/steps/preparechangelogfordepsroll.py +++ b/Tools/Scripts/webkitpy/tool/steps/preparechangelogfordepsroll.py @@ -34,7 +34,7 @@ from webkitpy.tool.steps.abstractstep import AbstractStep class PrepareChangeLogForDEPSRoll(AbstractStep): def run(self, state): - self._run_script("prepare-ChangeLog") + self._tool.executive.run_and_throw_if_fail(self._tool.port().prepare_changelog_command()) changelog_paths = self._tool.checkout().modified_changelogs(git_commit=None) for changelog_path in changelog_paths: ChangeLog(changelog_path).update_with_unreviewed_message("Rolled DEPS.\n\n") diff --git a/Tools/Scripts/webkitpy/tool/steps/preparechangelogforrevert.py b/Tools/Scripts/webkitpy/tool/steps/preparechangelogforrevert.py index dcd4b93..0a47573 100644 --- a/Tools/Scripts/webkitpy/tool/steps/preparechangelogforrevert.py +++ b/Tools/Scripts/webkitpy/tool/steps/preparechangelogforrevert.py @@ -50,7 +50,7 @@ class PrepareChangeLogForRevert(AbstractStep): def run(self, state): # This could move to prepare-ChangeLog by adding a --revert= option. - self._run_script("prepare-ChangeLog") + self._tool.executive.run_and_throw_if_fail(self._tool.port().prepare_changelog_command()) changelog_paths = self._tool.checkout().modified_changelogs(git_commit=None) bug_url = self._tool.bugs.bug_url_for_bug_id(state["bug_id"]) if state["bug_id"] else None message = self._message_for_revert(state["revision_list"], state["reason"], bug_url) diff --git a/Tools/Scripts/webkitpy/tool/steps/runtests.py b/Tools/Scripts/webkitpy/tool/steps/runtests.py index 282e381..793a94b 100644 --- a/Tools/Scripts/webkitpy/tool/steps/runtests.py +++ b/Tools/Scripts/webkitpy/tool/steps/runtests.py @@ -31,6 +31,9 @@ from webkitpy.tool.steps.options import Options from webkitpy.common.system.deprecated_logging import log class RunTests(AbstractStep): + # FIXME: This knowledge really belongs in the commit-queue. + NON_INTERACTIVE_FAILURE_LIMIT_COUNT = 10 + @classmethod def options(cls): return AbstractStep.options() + [ @@ -59,21 +62,8 @@ class RunTests(AbstractStep): if self._options.non_interactive: args.append("--no-new-test-results") args.append("--no-launch-safari") - args.append("--exit-after-n-failures=1") + args.append("--exit-after-n-failures=%s" % self.NON_INTERACTIVE_FAILURE_LIMIT_COUNT) args.append("--wait-for-httpd") - # FIXME: Hack to work around https://bugs.webkit.org/show_bug.cgi?id=38912 - # when running the commit-queue on a mac leopard machine since compositing - # does not work reliably on Leopard due to various graphics driver/system bugs. - if self._tool.port().name() == "Mac" and self._tool.port().is_leopard(): - tests_to_ignore = [] - tests_to_ignore.append("compositing") - - # media tests are also broken on mac leopard due to - # a separate CoreVideo bug which causes random crashes/hangs - # https://bugs.webkit.org/show_bug.cgi?id=38912 - tests_to_ignore.append("media") - - args.extend(["--ignore-tests", ",".join(tests_to_ignore)]) if self._options.quiet: args.append("--quiet") diff --git a/Tools/Scripts/webkitpy/tool/steps/steps_unittest.py b/Tools/Scripts/webkitpy/tool/steps/steps_unittest.py index 783ae29..e1ace2c 100644 --- a/Tools/Scripts/webkitpy/tool/steps/steps_unittest.py +++ b/Tools/Scripts/webkitpy/tool/steps/steps_unittest.py @@ -66,17 +66,12 @@ class StepsTest(unittest.TestCase): tool.user.prompt = lambda message: 42 self._run_step(PromptForBugOrTitle, tool=tool) - def test_runtests_leopard_commit_queue_hack_step(self): - expected_stderr = "Running Python unit tests\nRunning Perl unit tests\nRunning JavaScriptCore tests\nRunning run-webkit-tests\n" - OutputCapture().assert_outputs(self, self._run_step, [RunTests], expected_stderr=expected_stderr) - - def test_runtests_leopard_commit_queue_hack_command(self): + def test_runtests_args(self): mock_options = self._step_options() step = RunTests(MockTool(log_executive=True), mock_options) # FIXME: We shouldn't use a real port-object here, but there is too much to mock at the moment. mock_port = WebKitPort() mock_port.name = lambda: "Mac" - mock_port.is_leopard = lambda: True tool = MockTool(log_executive=True) tool.port = lambda: mock_port step = RunTests(tool, mock_options) @@ -87,6 +82,6 @@ MOCK run_and_throw_if_fail: ['Tools/Scripts/test-webkitperl'] Running JavaScriptCore tests MOCK run_and_throw_if_fail: ['Tools/Scripts/run-javascriptcore-tests'] Running run-webkit-tests -MOCK run_and_throw_if_fail: ['Tools/Scripts/run-webkit-tests', '--no-new-test-results', '--no-launch-safari', '--exit-after-n-failures=1', '--wait-for-httpd', '--ignore-tests', 'compositing,media', '--quiet'] +MOCK run_and_throw_if_fail: ['Tools/Scripts/run-webkit-tests', '--no-new-test-results', '--no-launch-safari', '--exit-after-n-failures=10', '--wait-for-httpd', '--quiet'] """ OutputCapture().assert_outputs(self, step.run, [{}], expected_stderr=expected_stderr) diff --git a/Tools/TestResultServer/handlers/dashboardhandler.py b/Tools/TestResultServer/handlers/dashboardhandler.py index fbbd56b..cae2b13 100644 --- a/Tools/TestResultServer/handlers/dashboardhandler.py +++ b/Tools/TestResultServer/handlers/dashboardhandler.py @@ -89,6 +89,7 @@ class UpdateDashboardFile(webapp.RequestHandler): if not files: # FIXME: Just grab the entire dashboards directory. files = ["aggregate_results.html", + "builders.js", "dashboard_base.js", "dygraph-combined.js", "flakiness_dashboard.html", diff --git a/Tools/TestWebKitAPI/Configurations/TestWebKitAPIRelease.vsprops b/Tools/TestWebKitAPI/Configurations/TestWebKitAPIRelease.vsprops index e7a103c..ebb1f34 100644 --- a/Tools/TestWebKitAPI/Configurations/TestWebKitAPIRelease.vsprops +++ b/Tools/TestWebKitAPI/Configurations/TestWebKitAPIRelease.vsprops @@ -3,6 +3,12 @@ ProjectType="Visual C++" Version="8.00" Name="TestWebKitAPIRelease" - InheritedPropertySheets="$(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\common.vsprops;$(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\release.vsprops;.\TestWebKitAPICommon.vsprops;.\TestWebKitAPICoreFoundation.vsprops;.\TestWebKitAPICFNetwork.vsprops" + InheritedPropertySheets=" + $(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\common.vsprops; + $(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\releaseproduction.vsprops; + $(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\release.vsprops; + .\TestWebKitAPICommon.vsprops; + .\TestWebKitAPICoreFoundation.vsprops; + .\TestWebKitAPICFNetwork.vsprops" > </VisualStudioPropertySheet> diff --git a/Tools/TestWebKitAPI/Configurations/TestWebKitAPIReleaseCairoCFLite.vsprops b/Tools/TestWebKitAPI/Configurations/TestWebKitAPIReleaseCairoCFLite.vsprops index 512eca6..400144d 100644 --- a/Tools/TestWebKitAPI/Configurations/TestWebKitAPIReleaseCairoCFLite.vsprops +++ b/Tools/TestWebKitAPI/Configurations/TestWebKitAPIReleaseCairoCFLite.vsprops @@ -3,6 +3,12 @@ ProjectType="Visual C++" Version="8.00" Name="TestWebKitAPIReleaseCairoCFLite" - InheritedPropertySheets="$(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\common.vsprops;$(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\release.vsprops;$(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\WinCairo.vsprops;..\Configurations\TestWebKitAPICommon.vsprops;..\Configurations\TestWebKitAPICFLite.vsprops" + InheritedPropertySheets=" + $(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\common.vsprops; + $(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\releaseproduction.vsprops; + $(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\release.vsprops; + $(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\WinCairo.vsprops; + ..\Configurations\TestWebKitAPICommon.vsprops; + ..\Configurations\TestWebKitAPICFLite.vsprops" > </VisualStudioPropertySheet> diff --git a/Tools/TestWebKitAPI/PlatformUtilities.h b/Tools/TestWebKitAPI/PlatformUtilities.h index a682545..dc1dc13 100644 --- a/Tools/TestWebKitAPI/PlatformUtilities.h +++ b/Tools/TestWebKitAPI/PlatformUtilities.h @@ -28,6 +28,7 @@ #include <WebKit2/WebKit2.h> #include <WebKit2/WKRetainPtr.h> +#include <wtf/Platform.h> #include <string> namespace TestWebKitAPI { @@ -36,6 +37,10 @@ namespace Util { // Runs a platform runloop until the 'done' is true. void run(bool* done); +#if PLATFORM(WIN) +bool shouldTranslateMessage(const MSG&); +#endif + void sleep(double seconds); WKContextRef createContextForInjectedBundleTest(const std::string&, WKTypeRef userData = 0); @@ -50,11 +55,6 @@ bool isKeyDown(WKNativeEventPtr); std::string toSTD(WKStringRef string); WKRetainPtr<WKStringRef> toWK(const char* utf8String); -template<typename T> static inline WKRetainPtr<T> adoptWK(T item) -{ - return WKRetainPtr<T>(AdoptWK, item); -} - } // namespace Util } // namespace TestWebKitAPI diff --git a/Tools/TestWebKitAPI/PlatformWebView.h b/Tools/TestWebKitAPI/PlatformWebView.h index 3d1698f..6a9bc27 100644 --- a/Tools/TestWebKitAPI/PlatformWebView.h +++ b/Tools/TestWebKitAPI/PlatformWebView.h @@ -27,7 +27,10 @@ #define PlatformWebView_h #include <wtf/Platform.h> + +#if USE(CG) #include <CoreGraphics/CGGeometry.h> +#endif #ifdef __APPLE__ #ifdef __OBJC__ @@ -65,6 +68,7 @@ public: void simulateRightClick(unsigned x, unsigned y); #if PLATFORM(WIN) + void simulateAKeyDown(); void setParentWindowMessageObserver(WindowMessageObserver* observer) { m_parentWindowMessageObserver = observer; } #endif diff --git a/Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj b/Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj index c5c9555..86b691d 100644 --- a/Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj +++ b/Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj @@ -57,7 +57,6 @@ C0ADBE9612FCA79B00D2C129 /* simple-form.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = C0ADBE8412FCA6B600D2C129 /* simple-form.html */; }; C0BD669D131D3CF700E18F2A /* ResponsivenessTimerDoesntFireEarly.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C0BD669C131D3CF700E18F2A /* ResponsivenessTimerDoesntFireEarly.cpp */; }; C0BD669F131D3CFF00E18F2A /* ResponsivenessTimerDoesntFireEarly_Bundle.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C0BD669E131D3CFF00E18F2A /* ResponsivenessTimerDoesntFireEarly_Bundle.cpp */; }; - F6C59E38132AC5E000176C09 /* SendingMessagesToTheWebProcessBeforeItIsValid.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F6C59E37132AC5DF00176C09 /* SendingMessagesToTheWebProcessBeforeItIsValid.cpp */; }; F6F3F29113342FEB00A6BF19 /* CookieManager.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F6F3F29013342FEB00A6BF19 /* CookieManager.cpp */; }; /* End PBXBuildFile section */ @@ -161,7 +160,6 @@ C0ADBE8412FCA6B600D2C129 /* simple-form.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = "simple-form.html"; sourceTree = "<group>"; }; C0BD669C131D3CF700E18F2A /* ResponsivenessTimerDoesntFireEarly.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ResponsivenessTimerDoesntFireEarly.cpp; sourceTree = "<group>"; }; C0BD669E131D3CFF00E18F2A /* ResponsivenessTimerDoesntFireEarly_Bundle.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ResponsivenessTimerDoesntFireEarly_Bundle.cpp; sourceTree = "<group>"; }; - F6C59E37132AC5DF00176C09 /* SendingMessagesToTheWebProcessBeforeItIsValid.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SendingMessagesToTheWebProcessBeforeItIsValid.cpp; sourceTree = "<group>"; }; F6F3F29013342FEB00A6BF19 /* CookieManager.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CookieManager.cpp; sourceTree = "<group>"; }; /* End PBXFileReference section */ @@ -289,7 +287,6 @@ C0BD669C131D3CF700E18F2A /* ResponsivenessTimerDoesntFireEarly.cpp */, C0BD669E131D3CFF00E18F2A /* ResponsivenessTimerDoesntFireEarly_Bundle.cpp */, C0ADBE8212FCA6AA00D2C129 /* RestoreSessionStateContainingFormData.cpp */, - F6C59E37132AC5DF00176C09 /* SendingMessagesToTheWebProcessBeforeItIsValid.cpp */, C02B77F1126612140026BF0F /* SpacebarScrolling.cpp */, BC7B619A1299FE9E00D174A4 /* WKPreferences.cpp */, BC90995D12567BC100083756 /* WKString.cpp */, @@ -444,7 +441,6 @@ 1ADBEFAE130C689C00D61D19 /* ForceRepaint.cpp in Sources */, 4BFDFFA9131477770061F24B /* HitTestResultNodeHandle.cpp in Sources */, C0BD669D131D3CF700E18F2A /* ResponsivenessTimerDoesntFireEarly.cpp in Sources */, - F6C59E38132AC5E000176C09 /* SendingMessagesToTheWebProcessBeforeItIsValid.cpp in Sources */, BC246D8E132F115A00B56D7C /* AboutBlankLoad.cpp in Sources */, BC246D9A132F1FE100B56D7C /* CanHandleRequest.cpp in Sources */, F6F3F29113342FEB00A6BF19 /* CookieManager.cpp in Sources */, diff --git a/Tools/TestWebKitAPI/Tests/WebKit2/AboutBlankLoad.cpp b/Tools/TestWebKitAPI/Tests/WebKit2/AboutBlankLoad.cpp index 27180e3..cb00276 100644 --- a/Tools/TestWebKitAPI/Tests/WebKit2/AboutBlankLoad.cpp +++ b/Tools/TestWebKitAPI/Tests/WebKit2/AboutBlankLoad.cpp @@ -43,7 +43,7 @@ static void decidePolicyForResponse(WKPageRef, WKFrameRef, WKURLResponseRef resp TEST(WebKit2, AboutBlankLoad) { - WKRetainPtr<WKContextRef> context = Util::adoptWK(WKContextCreate()); + WKRetainPtr<WKContextRef> context = adoptWK(WKContextCreate()); PlatformWebView webView(context.get()); WKPagePolicyClient policyClient; @@ -52,7 +52,7 @@ TEST(WebKit2, AboutBlankLoad) policyClient.decidePolicyForResponse = decidePolicyForResponse; WKPageSetPagePolicyClient(webView.page(), &policyClient); - WKPageLoadURL(webView.page(), Util::adoptWK(WKURLCreateWithUTF8CString("about:blank")).get()); + WKPageLoadURL(webView.page(), adoptWK(WKURLCreateWithUTF8CString("about:blank")).get()); Util::run(&done); } diff --git a/Tools/TestWebKitAPI/Tests/WebKit2/CanHandleRequest.cpp b/Tools/TestWebKitAPI/Tests/WebKit2/CanHandleRequest.cpp index 8460847..dffac9b 100644 --- a/Tools/TestWebKitAPI/Tests/WebKit2/CanHandleRequest.cpp +++ b/Tools/TestWebKitAPI/Tests/WebKit2/CanHandleRequest.cpp @@ -55,14 +55,14 @@ static void setInjectedBundleClient(WKContextRef context) TEST(WebKit2, CanHandleRequest) { - WKRetainPtr<WKContextRef> context = Util::adoptWK(Util::createContextForInjectedBundleTest("CanHandleRequestTest")); + WKRetainPtr<WKContextRef> context = adoptWK(Util::createContextForInjectedBundleTest("CanHandleRequestTest")); setInjectedBundleClient(context.get()); _WKContextRegisterURLSchemeAsEmptyDocument(context.get(), Util::toWK("emptyscheme").get()); PlatformWebView webView(context.get()); - WKPageLoadURL(webView.page(), Util::adoptWK(Util::createURLForResource("simple", "html")).get()); + WKPageLoadURL(webView.page(), adoptWK(Util::createURLForResource("simple", "html")).get()); WKContextPostMessageToInjectedBundle(context.get(), Util::toWK("CheckCanHandleRequest").get(), 0); Util::run(&didReceiveMessage); diff --git a/Tools/TestWebKitAPI/Tests/WebKit2/CanHandleRequest_Bundle.cpp b/Tools/TestWebKitAPI/Tests/WebKit2/CanHandleRequest_Bundle.cpp index a253362..b5d644d 100644 --- a/Tools/TestWebKitAPI/Tests/WebKit2/CanHandleRequest_Bundle.cpp +++ b/Tools/TestWebKitAPI/Tests/WebKit2/CanHandleRequest_Bundle.cpp @@ -47,7 +47,7 @@ CanHandleRequestTest::CanHandleRequestTest(const std::string& identifier) static bool canHandleURL(const char* url) { - return WKBundlePageCanHandleRequest(Util::adoptWK(WKURLRequestCreateWithWKURL(Util::adoptWK(WKURLCreateWithUTF8CString(url)).get())).get()); + return WKBundlePageCanHandleRequest(adoptWK(WKURLRequestCreateWithWKURL(adoptWK(WKURLCreateWithUTF8CString(url)).get())).get()); } static bool runTest() @@ -60,7 +60,7 @@ void CanHandleRequestTest::didReceiveMessage(WKBundleRef bundle, WKStringRef mes if (!WKStringIsEqualToUTF8CString(messageName, "CheckCanHandleRequest")) return; - WKBundlePostMessage(bundle, Util::toWK("DidCheckCanHandleRequest").get(), Util::adoptWK(WKBooleanCreate(runTest())).get()); + WKBundlePostMessage(bundle, Util::toWK("DidCheckCanHandleRequest").get(), adoptWK(WKBooleanCreate(runTest())).get()); } } // namespace TestWebKitAPI diff --git a/Tools/TestWebKitAPI/Tests/WebKit2/CookieManager.cpp b/Tools/TestWebKitAPI/Tests/WebKit2/CookieManager.cpp index cc4fc43..a1c366c 100644 --- a/Tools/TestWebKitAPI/Tests/WebKit2/CookieManager.cpp +++ b/Tools/TestWebKitAPI/Tests/WebKit2/CookieManager.cpp @@ -80,7 +80,7 @@ TEST(WebKit2, CookieManager) loaderClient.didFinishLoadForFrame = didFinishLoadForFrame; WKPageSetPageLoaderClient(webView.page(), &loaderClient); - WKPageLoadURL(webView.page(), Util::adoptWK(WKURLCreateWithUTF8CString("about:blank")).get()); + WKPageLoadURL(webView.page(), adoptWK(WKURLCreateWithUTF8CString("about:blank")).get()); Util::run(&testDone); } diff --git a/Tools/TestWebKitAPI/Tests/WebKit2/HitTestResultNodeHandle.cpp b/Tools/TestWebKitAPI/Tests/WebKit2/HitTestResultNodeHandle.cpp index 5000a47..3f15c15 100644 --- a/Tools/TestWebKitAPI/Tests/WebKit2/HitTestResultNodeHandle.cpp +++ b/Tools/TestWebKitAPI/Tests/WebKit2/HitTestResultNodeHandle.cpp @@ -77,7 +77,7 @@ TEST(WebKit2, HitTestResultNodeHandle) PlatformWebView webView(context.get()); setPageLoaderClient(webView.page()); - WKPageLoadURL(webView.page(), Util::adoptWK(Util::createURLForResource("simple", "html")).get()); + WKPageLoadURL(webView.page(), adoptWK(Util::createURLForResource("simple", "html")).get()); Util::run(&didFinishLoad); didFinishLoad = false; diff --git a/Tools/TestWebKitAPI/Tests/WebKit2/PageLoadDidChangeLocationWithinPageForFrame.cpp b/Tools/TestWebKitAPI/Tests/WebKit2/PageLoadDidChangeLocationWithinPageForFrame.cpp index a492a67..ce7324b 100644 --- a/Tools/TestWebKitAPI/Tests/WebKit2/PageLoadDidChangeLocationWithinPageForFrame.cpp +++ b/Tools/TestWebKitAPI/Tests/WebKit2/PageLoadDidChangeLocationWithinPageForFrame.cpp @@ -72,12 +72,12 @@ TEST(WebKit2, PageLoadDidChangeLocationWithinPageForFrame) WKPageLoadURL(webView.page(), url.get()); Util::run(&didFinishLoad); - WKRetainPtr<WKURLRef> initialURL = Util::adoptWK(WKFrameCopyURL(WKPageGetMainFrame(webView.page()))); + WKRetainPtr<WKURLRef> initialURL = adoptWK(WKFrameCopyURL(WKPageGetMainFrame(webView.page()))); WKPageRunJavaScriptInMainFrame(webView.page(), Util::toWK("clickLink()").get(), 0, nullJavaScriptCallback); Util::run(&didChangeLocationWithinPage); - WKRetainPtr<WKURLRef> urlAfterAnchorClick = Util::adoptWK(WKFrameCopyURL(WKPageGetMainFrame(webView.page()))); + WKRetainPtr<WKURLRef> urlAfterAnchorClick = adoptWK(WKFrameCopyURL(WKPageGetMainFrame(webView.page()))); TEST_ASSERT(!WKURLIsEqual(initialURL.get(), urlAfterAnchorClick.get())); } diff --git a/Tools/TestWebKitAPI/Tests/WebKit2/ResponsivenessTimerDoesntFireEarly.cpp b/Tools/TestWebKitAPI/Tests/WebKit2/ResponsivenessTimerDoesntFireEarly.cpp index ea1013a..d8273a1 100644 --- a/Tools/TestWebKitAPI/Tests/WebKit2/ResponsivenessTimerDoesntFireEarly.cpp +++ b/Tools/TestWebKitAPI/Tests/WebKit2/ResponsivenessTimerDoesntFireEarly.cpp @@ -75,13 +75,13 @@ static void setPageLoaderClient(WKPageRef page) TEST(WebKit2, ResponsivenessTimerDoesntFireEarly) { - WKRetainPtr<WKContextRef> context = Util::adoptWK(Util::createContextForInjectedBundleTest("ResponsivenessTimerDoesntFireEarlyTest")); + WKRetainPtr<WKContextRef> context = adoptWK(Util::createContextForInjectedBundleTest("ResponsivenessTimerDoesntFireEarlyTest")); setInjectedBundleClient(context.get()); PlatformWebView webView(context.get()); setPageLoaderClient(webView.page()); - WKPageLoadURL(webView.page(), Util::adoptWK(Util::createURLForResource("simple", "html")).get()); + WKPageLoadURL(webView.page(), adoptWK(Util::createURLForResource("simple", "html")).get()); Util::run(&didFinishLoad); WKContextPostMessageToInjectedBundle(context.get(), Util::toWK("BrieflyPause").get(), 0); diff --git a/Tools/TestWebKitAPI/Tests/WebKit2/RestoreSessionStateContainingFormData.cpp b/Tools/TestWebKitAPI/Tests/WebKit2/RestoreSessionStateContainingFormData.cpp index 7c08735..0970bd2 100644 --- a/Tools/TestWebKitAPI/Tests/WebKit2/RestoreSessionStateContainingFormData.cpp +++ b/Tools/TestWebKitAPI/Tests/WebKit2/RestoreSessionStateContainingFormData.cpp @@ -53,7 +53,7 @@ static WKRetainPtr<WKDataRef> createSessionStateContainingFormData(WKContextRef PlatformWebView webView(context); setPageLoaderClient(webView.page()); - WKPageLoadURL(webView.page(), Util::adoptWK(Util::createURLForResource("simple-form", "html")).get()); + WKPageLoadURL(webView.page(), adoptWK(Util::createURLForResource("simple-form", "html")).get()); Util::run(&didFinishLoad); didFinishLoad = false; @@ -61,7 +61,7 @@ static WKRetainPtr<WKDataRef> createSessionStateContainingFormData(WKContextRef Util::run(&didFinishLoad); didFinishLoad = false; - return Util::adoptWK(WKPageCopySessionState(webView.page(), 0, 0)); + return adoptWK(WKPageCopySessionState(webView.page(), 0, 0)); } TEST(WebKit2, RestoreSessionStateContainingFormData) diff --git a/Tools/TestWebKitAPI/Tests/WebKit2/SendingMessagesToTheWebProcessBeforeItIsValid.cpp b/Tools/TestWebKitAPI/Tests/WebKit2/SendingMessagesToTheWebProcessBeforeItIsValid.cpp deleted file mode 100644 index d48ba31..0000000 --- a/Tools/TestWebKitAPI/Tests/WebKit2/SendingMessagesToTheWebProcessBeforeItIsValid.cpp +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright (C) 2011 Apple 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. - * - * THIS SOFTWARE IS PROVIDED BY APPLE INC. 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 INC. 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. - */ - -#include "Test.h" - -#include <WebKit2/WKRetainPtr.h> -#include <WebKit2/WKContext.h> - -namespace TestWebKitAPI { - -TEST(WebKit2, SendingMessagesToTheWebProcessBeforeItIsValid) -{ - WKRetainPtr<WKContextRef> context(AdoptWK, WKContextCreate()); - - // Neither of these calls should cause a crash. - WKContextClearResourceCaches(context.get(), kWKAllResourceCaches); - WKContextClearResourceCaches(context.get(), kWKInMemoryResourceCachesOnly); -} - -} // namespace TestWebKitAPI diff --git a/Tools/TestWebKitAPI/Tests/WebKit2/WKString.cpp b/Tools/TestWebKitAPI/Tests/WebKit2/WKString.cpp index b0b133d..4202417 100644 --- a/Tools/TestWebKitAPI/Tests/WebKit2/WKString.cpp +++ b/Tools/TestWebKitAPI/Tests/WebKit2/WKString.cpp @@ -46,6 +46,27 @@ TEST(WebKit2, WKString) delete[] buffer; + maxSize = WKStringGetLength(string); + TEST_ASSERT(maxSize == 5); + + // Allocate a buffer one character larger than we need. + WKChar* uniBuffer = new WKChar[maxSize+1]; + actualSize = WKStringGetCharacters(string, uniBuffer, maxSize); + TEST_ASSERT(actualSize == 5); + + WKChar helloBuffer[] = { 'h', 'e', 'l', 'l', 'o' }; + TEST_ASSERT(!memcmp(uniBuffer, helloBuffer, 10)); + + // Test passing a buffer length < the string length. + actualSize = WKStringGetCharacters(string, uniBuffer, maxSize-1); + TEST_ASSERT(actualSize == 4); + + // Test passing a buffer length > the string length. + actualSize = WKStringGetCharacters(string, uniBuffer, maxSize+1); + TEST_ASSERT(actualSize == 5); + + delete[] uniBuffer; + WKRelease(string); } diff --git a/Tools/TestWebKitAPI/Tests/WebKit2/win/HideFindIndicator.cpp b/Tools/TestWebKitAPI/Tests/WebKit2/win/HideFindIndicator.cpp index 40d4f41..7f0c6fa 100644 --- a/Tools/TestWebKitAPI/Tests/WebKit2/win/HideFindIndicator.cpp +++ b/Tools/TestWebKitAPI/Tests/WebKit2/win/HideFindIndicator.cpp @@ -63,7 +63,7 @@ TEST(WebKit2, HideFindIndicator) PlatformWebView webView(context.get()); initialize(webView); - WKRetainPtr<WKURLRef> url = Util::adoptWK(Util::createURLForResource("find", "html")); + WKRetainPtr<WKURLRef> url = adoptWK(Util::createURLForResource("find", "html")); WKPageLoadURL(webView.page(), url.get()); Util::run(&didFinishLoad); didFinishLoad = false; diff --git a/Tools/TestWebKitAPI/Tests/WebKit2/win/ResizeViewWhileHidden.cpp b/Tools/TestWebKitAPI/Tests/WebKit2/win/ResizeViewWhileHidden.cpp index 7310e6c..9ebfc2c 100644 --- a/Tools/TestWebKitAPI/Tests/WebKit2/win/ResizeViewWhileHidden.cpp +++ b/Tools/TestWebKitAPI/Tests/WebKit2/win/ResizeViewWhileHidden.cpp @@ -55,7 +55,7 @@ static void flushMessages(WKPageRef page) setPageLoaderClient(page); - WKPageLoadURL(page, Util::adoptWK(Util::createURLForResource("simple", "html")).get()); + WKPageLoadURL(page, adoptWK(Util::createURLForResource("simple", "html")).get()); Util::run(&didFinishLoad); didFinishLoad = false; diff --git a/Tools/TestWebKitAPI/Tests/WebKit2/win/TranslateMessageGeneratesWMChar.cpp b/Tools/TestWebKitAPI/Tests/WebKit2/win/TranslateMessageGeneratesWMChar.cpp new file mode 100644 index 0000000..66b1291 --- /dev/null +++ b/Tools/TestWebKitAPI/Tests/WebKit2/win/TranslateMessageGeneratesWMChar.cpp @@ -0,0 +1,91 @@ +/* + * Copyright (C) 2011 Apple 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. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. 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 INC. 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. + */ + +#include "Test.h" + +#include "PlatformUtilities.h" +#include "PlatformWebView.h" +#include "WindowMessageObserver.h" +#include <WebKit2/WKRetainPtr.h> + +namespace TestWebKitAPI { + +static bool didSeeWMChar; +static bool didNotHandleKeyEventCalled; + +static void didNotHandleKeyEventCallback(WKPageRef, WKNativeEventPtr event, const void*) +{ + if (event->message != WM_KEYDOWN) + return; + + // Don't call TranslateMessage() here so a WM_CHAR isn't generated. + didNotHandleKeyEventCalled = true; +} + +static void runAndWatchForWMChar(bool* done) +{ + while (!*done) { + MSG msg; + BOOL result = ::GetMessageW(&msg, 0, 0, 0); + if (!result || result == -1) + break; + + if (msg.message == WM_CHAR) + didSeeWMChar = true; + + if (Util::shouldTranslateMessage(msg)) + ::TranslateMessage(&msg); + + ::DispatchMessage(&msg); + } +} + +TEST(WebKit2, TranslateMessageGeneratesWMChar) +{ + WKRetainPtr<WKContextRef> context(AdoptWK, WKContextCreate()); + PlatformWebView webView(context.get()); + + webView.simulateAKeyDown(); + + // WebKit should call TranslateMessage() on the WM_KEYDOWN message to generate the WM_CHAR message. + runAndWatchForWMChar(&didSeeWMChar); + + didSeeWMChar = false; + + WKPageUIClient uiClient; + memset(&uiClient, 0, sizeof(uiClient)); + + uiClient.didNotHandleKeyEvent = didNotHandleKeyEventCallback; + WKPageSetPageUIClient(webView.page(), &uiClient); + + webView.simulateAKeyDown(); + + runAndWatchForWMChar(&didNotHandleKeyEventCalled); + + // WebKit should not have called TranslateMessage() on the WM_KEYDOWN message since we installed a didNotHandleKeyEvent callback. + TEST_ASSERT(!didSeeWMChar); +} + +} // namespace TestWebKitAPI diff --git a/Tools/TestWebKitAPI/win/PlatformUtilitiesWin.cpp b/Tools/TestWebKitAPI/win/PlatformUtilitiesWin.cpp index 181d88e..90208c5 100644 --- a/Tools/TestWebKitAPI/win/PlatformUtilitiesWin.cpp +++ b/Tools/TestWebKitAPI/win/PlatformUtilitiesWin.cpp @@ -49,11 +49,29 @@ void run(bool* done) BOOL result = ::GetMessageW(&msg, 0, 0, 0); if (!result || result == -1) break; - ::TranslateMessage(&msg); + + if (shouldTranslateMessage(msg)) + ::TranslateMessage(&msg); ::DispatchMessage(&msg); } } +bool shouldTranslateMessage(const MSG& msg) +{ + // Only these four messages are actually translated by ::TranslateMessage or ::TranslateAccelerator. + // It's useless (though harmless) to call those functions for other messages, so we always allow other messages to be translated. + if (msg.message != WM_KEYDOWN && msg.message != WM_SYSKEYDOWN && msg.message != WM_KEYUP && msg.message != WM_SYSKEYUP) + return true; + + wchar_t className[256]; + if (!::GetClassNameW(msg.hwnd, className, ARRAYSIZE(className))) + return true; + + // Don't call TranslateMessage() on key events destined for a WebKit2 view, WebKit will do this if it doesn't handle the message. + // It would be nice to use some API here instead of hard-coding the window class name. + return wcscmp(className, L"WebKit2WebViewWindowClass"); +} + void sleep(double seconds) { ::Sleep(seconds * 1000); diff --git a/Tools/TestWebKitAPI/win/PlatformWebViewWin.cpp b/Tools/TestWebKitAPI/win/PlatformWebViewWin.cpp index 132ab2a..1f39f8b 100644 --- a/Tools/TestWebKitAPI/win/PlatformWebViewWin.cpp +++ b/Tools/TestWebKitAPI/win/PlatformWebViewWin.cpp @@ -92,6 +92,14 @@ void PlatformWebView::simulateSpacebarKeyPress() ::SendMessageW(window, WM_KEYUP, VK_SPACE, (1 << repeatCountBitOffset) | (39 << scanCodeBitOffset) | (1 << previousStateBitOffset) | (1 << transitionStateBitOffset)); } +void PlatformWebView::simulateAKeyDown() +{ + HWND window = WKViewGetWindow(m_view); + + // These values match what happens when you press the 'A' key in Notepad, as observed by Spy++. + ::SendMessageW(window, WM_KEYDOWN, 'A', (1 << repeatCountBitOffset) | (30 << scanCodeBitOffset)); +} + void PlatformWebView::simulateAltKeyPress() { HWND window = WKViewGetWindow(m_view); diff --git a/Tools/TestWebKitAPI/win/TestWebKitAPI.vcproj b/Tools/TestWebKitAPI/win/TestWebKitAPI.vcproj index 468ed71..930f7f8 100644 --- a/Tools/TestWebKitAPI/win/TestWebKitAPI.vcproj +++ b/Tools/TestWebKitAPI/win/TestWebKitAPI.vcproj @@ -492,10 +492,6 @@ > </File> <File - RelativePath="..\Tests\WebKit2\SendingMessagesToTheWebProcessBeforeItIsValid.cpp" - > - </File> - <File RelativePath="..\Tests\WebKit2\simple-accelerated-compositing.html" > </File> @@ -563,6 +559,10 @@ > </File> <File + RelativePath="..\Tests\WebKit2\win\TranslateMessageGeneratesWMChar.cpp" + > + </File> + <File RelativePath="..\Tests\WebKit2\win\WMCloseCallsUIClientClose.cpp" > </File> diff --git a/Tools/Tools.pro b/Tools/Tools.pro index ca4ba3d..2e3d96e 100644 --- a/Tools/Tools.pro +++ b/Tools/Tools.pro @@ -7,7 +7,7 @@ exists($$PWD/DumpRenderTree/qt/ImageDiff.pro): SUBDIRS += DumpRenderTree/qt/Imag webkit2 { exists($$PWD/MiniBrowser/qt/MiniBrowser.pro): SUBDIRS += MiniBrowser/qt/MiniBrowser.pro - exists($$PWD/WebKitTestRunner/WebKitTestRunner.pro): SUBDIRS += WebKitTestRunner/WebKitTestRunner.pro + !symbian:exists($$PWD/WebKitTestRunner/WebKitTestRunner.pro): SUBDIRS += WebKitTestRunner/WebKitTestRunner.pro } !win32:!symbian { diff --git a/Tools/WebKitAPITest/WebKitAPITestProduction.vsprops b/Tools/WebKitAPITest/WebKitAPITestProduction.vsprops index 45cb5c9..56e6b7a 100644 --- a/Tools/WebKitAPITest/WebKitAPITestProduction.vsprops +++ b/Tools/WebKitAPITest/WebKitAPITestProduction.vsprops @@ -5,7 +5,7 @@ Name="WebKitAPITestProduction" InheritedPropertySheets=" $(WebKitVSPropsRedirectionDir)..\..\WebKitLibraries\win\tools\vsprops\common.vsprops; - $(WebKitVSPropsRedirectionDir)..\..\WebKitLibraries\win\tools\vsprops\release.vsprops; + $(WebKitVSPropsRedirectionDir)..\..\WebKitLibraries\win\tools\vsprops\releaseproduction.vsprops; $(WebKitVSPropsRedirectionDir)..\..\WebKitLibraries\win\tools\vsprops\production.vsprops; .\WebKitAPITestCommon.vsprops" > diff --git a/Tools/WebKitAPITest/WebKitAPITestRelease.vsprops b/Tools/WebKitAPITest/WebKitAPITestRelease.vsprops index e89d3e7..25167ba 100644 --- a/Tools/WebKitAPITest/WebKitAPITestRelease.vsprops +++ b/Tools/WebKitAPITest/WebKitAPITestRelease.vsprops @@ -5,6 +5,7 @@ Name="WebKitAPITestRelease" InheritedPropertySheets=" $(WebKitVSPropsRedirectionDir)..\..\WebKitLibraries\win\tools\vsprops\common.vsprops; + $(WebKitVSPropsRedirectionDir)..\..\WebKitLibraries\win\tools\vsprops\releaseproduction.vsprops; $(WebKitVSPropsRedirectionDir)..\..\WebKitLibraries\win\tools\vsprops\release.vsprops; .\WebKitAPITestCommon.vsprops" > diff --git a/Tools/WebKitAPITest/WebKitAPITestReleaseCairoCFLite.vsprops b/Tools/WebKitAPITest/WebKitAPITestReleaseCairoCFLite.vsprops index 8c1a3c3..ba93747 100644 --- a/Tools/WebKitAPITest/WebKitAPITestReleaseCairoCFLite.vsprops +++ b/Tools/WebKitAPITest/WebKitAPITestReleaseCairoCFLite.vsprops @@ -5,6 +5,7 @@ Name="WebKitAPITestReleaseCairoCFLite" InheritedPropertySheets=" $(WebKitVSPropsRedirectionDir)..\..\WebKitLibraries\win\tools\vsprops\common.vsprops; + $(WebKitVSPropsRedirectionDir)..\..\WebKitLibraries\win\tools\vsprops\releaseproduction.vsprops; $(WebKitVSPropsRedirectionDir)..\..\WebKitLibraries\win\tools\vsprops\release.vsprops; $(WebKitVSPropsRedirectionDir)..\..\WebKitLibraries\win\tools\vsprops\WinCairo.vsprops; .\WebKitAPITestCommon.vsprops" diff --git a/Tools/WebKitAPITest/config.h b/Tools/WebKitAPITest/config.h index bee51ac..14b72ff 100644 --- a/Tools/WebKitAPITest/config.h +++ b/Tools/WebKitAPITest/config.h @@ -49,8 +49,8 @@ #define WEBKIT_EXPORTDATA #endif -#define WTF_EXPORT_PRIVATE JS_EXPORTDATA -#define JS_EXPORT_PRIVATE JS_EXPORTDATA +#define WTF_EXPORT_PRIVATE +#define JS_EXPORT_PRIVATE #endif /* USE(EXPORT_MACROS) */ diff --git a/Tools/WebKitLauncherWin/WebKitLauncherWinProduction.vsprops b/Tools/WebKitLauncherWin/WebKitLauncherWinProduction.vsprops index 853abfb..cf126a4 100644 --- a/Tools/WebKitLauncherWin/WebKitLauncherWinProduction.vsprops +++ b/Tools/WebKitLauncherWin/WebKitLauncherWinProduction.vsprops @@ -5,7 +5,7 @@ Name="WebKitLauncherWinProduction" InheritedPropertySheets=" $(WebKitVSPropsRedirectionDir)..\..\WebKitLibraries\win\tools\vsprops\common.vsprops; - $(WebKitVSPropsRedirectionDir)..\..\WebKitLibraries\win\tools\vsprops\release.vsprops; + $(WebKitVSPropsRedirectionDir)..\..\WebKitLibraries\win\tools\vsprops\releaseproduction.vsprops; $(WebKitVSPropsRedirectionDir)..\..\WebKitLibraries\win\tools\vsprops\production.vsprops; .\WebKitLauncherWinCommon.vsprops" > diff --git a/Tools/WebKitLauncherWin/WebKitLauncherWinRelease.vsprops b/Tools/WebKitLauncherWin/WebKitLauncherWinRelease.vsprops index 1b906ef..63a86ae 100644 --- a/Tools/WebKitLauncherWin/WebKitLauncherWinRelease.vsprops +++ b/Tools/WebKitLauncherWin/WebKitLauncherWinRelease.vsprops @@ -5,6 +5,7 @@ Name="WebKitLauncherWinRelease" InheritedPropertySheets=" $(WebKitVSPropsRedirectionDir)..\..\WebKitLibraries\win\tools\vsprops\common.vsprops; + $(WebKitVSPropsRedirectionDir)..\..\WebKitLibraries\win\tools\vsprops\releaseproduction.vsprops; $(WebKitVSPropsRedirectionDir)..\..\WebKitLibraries\win\tools\vsprops\release.vsprops; .\WebKitLauncherWinCommon.vsprops" > diff --git a/Tools/WebKitLauncherWin/WebKitLauncherWinReleaseCairoCFLite.vsprops b/Tools/WebKitLauncherWin/WebKitLauncherWinReleaseCairoCFLite.vsprops index d635f3e..0af7d39 100644 --- a/Tools/WebKitLauncherWin/WebKitLauncherWinReleaseCairoCFLite.vsprops +++ b/Tools/WebKitLauncherWin/WebKitLauncherWinReleaseCairoCFLite.vsprops @@ -5,6 +5,7 @@ Name="WebKitLauncherWinReleaseCairoCFLite" InheritedPropertySheets=" $(WebKitVSPropsRedirectionDir)..\..\WebKitLibraries\win\tools\vsprops\common.vsprops; + $(WebKitVSPropsRedirectionDir)..\..\WebKitLibraries\win\tools\vsprops\releaseproduction.vsprops; $(WebKitVSPropsRedirectionDir)..\..\WebKitLibraries\win\tools\vsprops\release.vsprops; $(WebKitVSPropsRedirectionDir)..\..\WebKitLibraries\win\tools\vsprops\WinCairo.vsprops; .\WebKitLauncherWinCommon.vsprops" diff --git a/Tools/WebKitTestRunner/InjectedBundle/Bindings/EventSendingController.idl b/Tools/WebKitTestRunner/InjectedBundle/Bindings/EventSendingController.idl index 1e47772..ec33502 100644 --- a/Tools/WebKitTestRunner/InjectedBundle/Bindings/EventSendingController.idl +++ b/Tools/WebKitTestRunner/InjectedBundle/Bindings/EventSendingController.idl @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010 Apple Inc. All rights reserved. + * Copyright (C) 2010, 2011 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -26,18 +26,17 @@ module WTR { interface EventSendingController { - [CustomArgumentHandling] void mouseDown(); - [CustomArgumentHandling] void mouseUp(); - [CustomArgumentHandling] void mouseMoveTo(); - [CustomArgumentHandling] void keyDown(); - [CustomArgumentHandling] void contextClick(); // CustomArgumentHandling only to throw exception while not implemented. - [CustomArgumentHandling] void leapForward(/*in unsigned long delay*/); // CustomArgumentHandling only to throw exception while not implemented. + void mouseDown(in long buttonNumber, in object modifierArray); + void mouseUp(in long buttonNumber, in object modifierArray); + void mouseMoveTo(in long x, in long y); + void leapForward(in long milliseconds); // Zoom functions. void textZoomIn(); void textZoomOut(); void zoomPageIn(); void zoomPageOut(); + void scalePageBy(in double scale, in double x, in double y); }; } diff --git a/Tools/WebKitTestRunner/InjectedBundle/Bindings/LayoutTestController.idl b/Tools/WebKitTestRunner/InjectedBundle/Bindings/LayoutTestController.idl index a331c64..0593840 100644 --- a/Tools/WebKitTestRunner/InjectedBundle/Bindings/LayoutTestController.idl +++ b/Tools/WebKitTestRunner/InjectedBundle/Bindings/LayoutTestController.idl @@ -39,6 +39,7 @@ module WTR { void dumpSelectionRect(); void dumpStatusCallbacks(); void dumpTitleChanges(); + void dumpFullScreenCallbacks(); // Special options. void keepWebHistory(); @@ -46,6 +47,8 @@ module WTR { void setCanOpenWindows(in boolean value); void setCloseRemainingWindowsWhenComplete(in boolean value); void setXSSAuditorEnabled(in boolean value); + void setAllowUniversalAccessFromFileURLs(in boolean value); + void setAllowFileAccessFromFileURLs(in boolean value); // Special DOM functions. void clearBackForwardList(); @@ -55,12 +58,19 @@ module WTR { boolean isCommandEnabled(in DOMString name); DOMString markerTextForListItem(in object element); unsigned long windowCount(); + object shadowRoot(in object element); // Repaint testing. void testRepaint(); void repaintSweepHorizontally(); void display(); + // Printing + int numberOfPages(in double pageWidthInPixels, in double pageHeightInPixels); + int pageNumberForElementById(in DOMString id, in double pageWidthInPixels, in double pageHeightInPixels); + DOMString pageSizeAndMarginsInPixels(in int pageIndex, in int width, in int height, in int marginTop, in int marginRight, in int marginBottom, in int marginLeft); + boolean isPageBoxVisible(in int pageIndex); + // Animation testing. int numberOfActiveAnimations(); boolean pauseAnimationAtTimeOnElementWithId(in DOMString animationName, in double time, in DOMString elementId); @@ -70,7 +80,12 @@ module WTR { // UserContent testing. void addUserScript(in DOMString source, in boolean runAtStart, in boolean allFrames); void addUserStyleSheet(in DOMString source, in boolean allFrames); - + + // Local storage API + void clearAllDatabases(); + void setDatabaseQuota(in unsigned long long quota); + DOMString pathToLocalResource(in DOMString url); + // Compositing testing. DOMString layerTreeAsText(); diff --git a/Tools/WebKitTestRunner/InjectedBundle/EventSendingController.cpp b/Tools/WebKitTestRunner/InjectedBundle/EventSendingController.cpp index cc1720e..0725a85 100644 --- a/Tools/WebKitTestRunner/InjectedBundle/EventSendingController.cpp +++ b/Tools/WebKitTestRunner/InjectedBundle/EventSendingController.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010 Apple Inc. All rights reserved. + * Copyright (C) 2010, 2011 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -29,7 +29,7 @@ #include "InjectedBundle.h" #include "InjectedBundlePage.h" #include "JSEventSendingController.h" -#include <WebKit2/WKBundlePage.h> +#include <WebKit2/WKBundleFrame.h> #include <WebKit2/WKBundlePagePrivate.h> #include <WebKit2/WKBundlePrivate.h> @@ -37,12 +37,67 @@ namespace WTR { static const float ZoomMultiplierRatio = 1.2f; +static bool operator==(const WKPoint& a, const WKPoint& b) +{ + return a.x == b.x && a.y == b.y; +} + +static WKEventModifiers parseModifier(JSStringRef modifier) +{ + if (JSStringIsEqualToUTF8CString(modifier, "ctrlKey")) + return kWKEventModifiersControlKey; + if (JSStringIsEqualToUTF8CString(modifier, "shiftKey") || JSStringIsEqualToUTF8CString(modifier, "rangeSelectionKey")) + return kWKEventModifiersShiftKey; + if (JSStringIsEqualToUTF8CString(modifier, "altKey")) + return kWKEventModifiersAltKey; + if (JSStringIsEqualToUTF8CString(modifier, "metaKey") || JSStringIsEqualToUTF8CString(modifier, "addSelectionKey")) + return kWKEventModifiersMetaKey; + return 0; +} + +static unsigned arrayLength(JSContextRef context, JSObjectRef array) +{ + JSRetainPtr<JSStringRef> lengthString(Adopt, JSStringCreateWithUTF8CString("length")); + JSValueRef lengthValue = JSObjectGetProperty(context, array, lengthString.get(), 0); + if (!lengthValue) + return 0; + return static_cast<unsigned>(JSValueToNumber(context, lengthValue, 0)); +} + +static WKEventModifiers parseModifierArray(JSContextRef context, JSValueRef arrayValue) +{ + if (!arrayValue) + return 0; + if (!JSValueIsObject(context, arrayValue)) + return 0; + JSObjectRef array = const_cast<JSObjectRef>(arrayValue); + unsigned length = arrayLength(context, array); + WKEventModifiers modifiers = 0; + for (unsigned i = 0; i < length; i++) { + JSValueRef exception = 0; + JSValueRef value = JSObjectGetPropertyAtIndex(context, array, i, &exception); + if (exception) + continue; + JSRetainPtr<JSStringRef> string(Adopt, JSValueToStringCopy(context, value, &exception)); + if (exception) + continue; + modifiers |= parseModifier(string.get()); + } + return modifiers; +} + PassRefPtr<EventSendingController> EventSendingController::create() { return adoptRef(new EventSendingController); } EventSendingController::EventSendingController() + : m_time(0) + , m_position() + , m_clickCount(0) + , m_clickTime(0) + , m_clickPosition() + , m_clickButton(kWKEventMouseButtonNoButton) { } @@ -55,40 +110,50 @@ JSClassRef EventSendingController::wrapperClass() return JSEventSendingController::eventSendingControllerClass(); } -static void setExceptionForString(JSContextRef context, JSValueRef* exception, const char* string) -{ - JSRetainPtr<JSStringRef> exceptionString(Adopt, JSStringCreateWithUTF8CString(string)); - *exception = JSValueMakeString(context, exceptionString.get()); -} - -void EventSendingController::mouseDown(JSContextRef context, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +void EventSendingController::mouseDown(int button, JSValueRef modifierArray) { - setExceptionForString(context, exception, "EventSender.mouseDown is not yet supported."); + WKBundlePageRef page = InjectedBundle::shared().page()->page(); + WKBundleFrameRef frame = WKBundlePageGetMainFrame(page); + JSContextRef context = WKBundleFrameGetJavaScriptContext(frame); + WKEventModifiers modifiers = parseModifierArray(context, modifierArray); + updateClickCount(button); + WKBundlePageSimulateMouseDown(page, button, m_position, m_clickCount, modifiers, m_time); } -void EventSendingController::mouseUp(JSContextRef context, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +void EventSendingController::mouseUp(int button, JSValueRef modifierArray) { - setExceptionForString(context, exception, "EventSender.mouseUp is not yet supported."); + WKBundlePageRef page = InjectedBundle::shared().page()->page(); + WKBundleFrameRef frame = WKBundlePageGetMainFrame(page); + JSContextRef context = WKBundleFrameGetJavaScriptContext(frame); + WKEventModifiers modifiers = parseModifierArray(context, modifierArray); + updateClickCount(button); + WKBundlePageSimulateMouseUp(page, button, m_position, m_clickCount, modifiers, m_time); } -void EventSendingController::mouseMoveTo(JSContextRef context, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +void EventSendingController::mouseMoveTo(int x, int y) { - setExceptionForString(context, exception, "EventSender.mouseMoveTo is not yet supported."); + m_position.x = x; + m_position.y = y; + WKBundlePageSimulateMouseMotion(InjectedBundle::shared().page()->page(), m_position, m_time); } -void EventSendingController::keyDown(JSContextRef context, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +void EventSendingController::leapForward(int milliseconds) { - setExceptionForString(context, exception, "EventSender.keyDown is not yet supported."); + m_time += milliseconds / 1000.0; } -void EventSendingController::contextClick(JSContextRef context, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +void EventSendingController::updateClickCount(WKEventMouseButton button) { - setExceptionForString(context, exception, "EventSender.contextClick is not yet supported."); -} + if (m_time - m_clickTime < 1 && m_position == m_clickPosition && button == m_clickButton) { + ++m_clickCount; + m_clickTime = m_time; + return; + } -void EventSendingController::leapForward(JSContextRef context, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) -{ - setExceptionForString(context, exception, "EventSender.leapForward is not yet supported."); + m_clickCount = 1; + m_clickTime = m_time; + m_clickPosition = m_position; + m_clickButton = button; } void EventSendingController::textZoomIn() @@ -127,6 +192,12 @@ void EventSendingController::zoomPageOut() WKBundlePageSetPageZoomFactor(InjectedBundle::shared().page()->page(), zoomFactor / ZoomMultiplierRatio); } +void EventSendingController::scalePageBy(double scale, double x, double y) +{ + WKPoint origin = { x, y }; + WKBundlePageSetScaleAtOrigin(InjectedBundle::shared().page()->page(), scale, origin); +} + // Object Creation void EventSendingController::makeWindowObject(JSContextRef context, JSObjectRef windowObject, JSValueRef* exception) diff --git a/Tools/WebKitTestRunner/InjectedBundle/EventSendingController.h b/Tools/WebKitTestRunner/InjectedBundle/EventSendingController.h index 400f60d..702b8e2 100644 --- a/Tools/WebKitTestRunner/InjectedBundle/EventSendingController.h +++ b/Tools/WebKitTestRunner/InjectedBundle/EventSendingController.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010 Apple Inc. All rights reserved. + * Copyright (C) 2010, 2011 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -27,6 +27,8 @@ #define EventSendingController_h #include "JSWrappable.h" +#include <WebKit2/WKEvent.h> +#include <WebKit2/WKGeometry.h> #include <wtf/PassRefPtr.h> namespace WTR { @@ -41,21 +43,30 @@ public: // JSWrappable virtual JSClassRef wrapperClass(); - void mouseDown(JSContextRef context, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception); - void mouseUp(JSContextRef context, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception); - void mouseMoveTo(JSContextRef context, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception); - void keyDown(JSContextRef context, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception); - void contextClick(JSContextRef context, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception); - void leapForward(JSContextRef context, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception); + void mouseDown(int button, JSValueRef modifierArray); + void mouseUp(int button, JSValueRef modifierArray); + void mouseMoveTo(int x, int y); + void leapForward(int milliseconds); // Zoom functions. void textZoomIn(); void textZoomOut(); void zoomPageIn(); void zoomPageOut(); + void scalePageBy(double scale, double x, double y); private: EventSendingController(); + + void updateClickCount(WKEventMouseButton); + + double m_time; + WKPoint m_position; + + int m_clickCount; + double m_clickTime; + WKPoint m_clickPosition; + WKEventMouseButton m_clickButton; }; } // namespace WTR diff --git a/Tools/WebKitTestRunner/InjectedBundle/InjectedBundle.cpp b/Tools/WebKitTestRunner/InjectedBundle/InjectedBundle.cpp index ec6b723..311530f 100644 --- a/Tools/WebKitTestRunner/InjectedBundle/InjectedBundle.cpp +++ b/Tools/WebKitTestRunner/InjectedBundle/InjectedBundle.cpp @@ -172,6 +172,8 @@ void InjectedBundle::beginTesting() WKBundleRemoveAllUserContent(m_bundle, m_pageGroup); page()->reset(); + + WKBundleClearAllDatabases(m_bundle); } void InjectedBundle::done() diff --git a/Tools/WebKitTestRunner/InjectedBundle/InjectedBundlePage.cpp b/Tools/WebKitTestRunner/InjectedBundle/InjectedBundlePage.cpp index 3b73174..911e08f 100644 --- a/Tools/WebKitTestRunner/InjectedBundle/InjectedBundlePage.cpp +++ b/Tools/WebKitTestRunner/InjectedBundle/InjectedBundlePage.cpp @@ -202,6 +202,16 @@ InjectedBundlePage::InjectedBundlePage(WKBundlePageRef page) }; WKBundlePageSetResourceLoadClient(m_page, &resourceLoadClient); + WKBundlePagePolicyClient policyClient = { + 0, + this, + decidePolicyForNavigationAction, + decidePolicyForNewWindowAction, + decidePolicyForResponse, + unableToImplementPolicy + }; + WKBundlePageSetPolicyClient(m_page, &policyClient); + WKBundlePageUIClient uiClient = { 0, this, @@ -234,6 +244,17 @@ InjectedBundlePage::InjectedBundlePage(WKBundlePageRef page) didChangeSelection }; WKBundlePageSetEditorClient(m_page, &editorClient); + +#if ENABLE(FULLSCREEN_API) + WKBundlePageFullScreenClient fullScreenClient = { + 0, + this, + supportsFullScreen, + enterFullScreenForElement, + exitFullScreenForElement, + }; + WKBundlePageSetFullScreenClient(m_page, &fullScreenClient); +#endif } InjectedBundlePage::~InjectedBundlePage() @@ -252,6 +273,9 @@ void InjectedBundlePage::reset() WKBundlePageSetPageZoomFactor(m_page, 1); WKBundlePageSetTextZoomFactor(m_page, 1); + WKPoint origin = { 0, 0 }; + WKBundlePageSetScaleAtOrigin(m_page, 1, origin); + m_previousTestBackForwardListItem = adoptWK(WKBundleBackForwardListCopyItemAtIndex(WKBundlePageGetBackForwardList(m_page), 0)); WKBundleFrameClearOpener(WKBundlePageGetMainFrame(m_page)); @@ -666,6 +690,48 @@ void InjectedBundlePage::didFailLoadForResource(WKBundlePageRef, WKBundleFrameRe { } + +// Policy Client Callbacks + +WKBundlePagePolicyAction InjectedBundlePage::decidePolicyForNavigationAction(WKBundlePageRef page, WKBundleFrameRef frame, WKBundleNavigationActionRef navigationAction, WKURLRequestRef request, WKTypeRef* userData, const void* clientInfo) +{ + return static_cast<InjectedBundlePage*>(const_cast<void*>(clientInfo))->decidePolicyForNavigationAction(page, frame, navigationAction, request, userData); +} + +WKBundlePagePolicyAction InjectedBundlePage::decidePolicyForNewWindowAction(WKBundlePageRef page, WKBundleFrameRef frame, WKBundleNavigationActionRef navigationAction, WKURLRequestRef request, WKStringRef frameName, WKTypeRef* userData, const void* clientInfo) +{ + return static_cast<InjectedBundlePage*>(const_cast<void*>(clientInfo))->decidePolicyForNewWindowAction(page, frame, navigationAction, request, frameName, userData); +} + +WKBundlePagePolicyAction InjectedBundlePage::decidePolicyForResponse(WKBundlePageRef page, WKBundleFrameRef frame, WKURLResponseRef response, WKURLRequestRef request, WKTypeRef* userData, const void* clientInfo) +{ + return static_cast<InjectedBundlePage*>(const_cast<void*>(clientInfo))->decidePolicyForResponse(page, frame, response, request, userData); +} + +void InjectedBundlePage::unableToImplementPolicy(WKBundlePageRef page, WKBundleFrameRef frame, WKErrorRef error, WKTypeRef* userData, const void* clientInfo) +{ + static_cast<InjectedBundlePage*>(const_cast<void*>(clientInfo))->unableToImplementPolicy(page, frame, error, userData); +} + +WKBundlePagePolicyAction InjectedBundlePage::decidePolicyForNavigationAction(WKBundlePageRef, WKBundleFrameRef, WKBundleNavigationActionRef, WKURLRequestRef request, WKTypeRef*) +{ + return WKBundlePagePolicyActionUse; +} + +WKBundlePagePolicyAction InjectedBundlePage::decidePolicyForNewWindowAction(WKBundlePageRef, WKBundleFrameRef, WKBundleNavigationActionRef, WKURLRequestRef, WKStringRef, WKTypeRef*) +{ + return WKBundlePagePolicyActionUse; +} + +WKBundlePagePolicyAction InjectedBundlePage::decidePolicyForResponse(WKBundlePageRef, WKBundleFrameRef, WKURLResponseRef, WKURLRequestRef, WKTypeRef*) +{ + return WKBundlePagePolicyActionUse; +} + +void InjectedBundlePage::unableToImplementPolicy(WKBundlePageRef, WKBundleFrameRef, WKErrorRef, WKTypeRef*) +{ +} + // UI Client Callbacks void InjectedBundlePage::willAddMessageToConsole(WKBundlePageRef page, WKStringRef message, uint32_t lineNumber, const void *clientInfo) @@ -693,13 +759,38 @@ void InjectedBundlePage::willRunJavaScriptPrompt(WKBundlePageRef page, WKStringR static_cast<InjectedBundlePage*>(const_cast<void*>(clientInfo))->willRunJavaScriptPrompt(message, defaultValue, frame); } +static string lastFileURLPathComponent(const string& path) +{ + size_t pos = path.find("file://"); + ASSERT(string::npos != pos); + + string tmpPath = path.substr(pos + 7); + if (tmpPath.empty()) + return tmpPath; + + // Remove the trailing delimiter + if (tmpPath[tmpPath.length() - 1] == '/') + tmpPath.erase(tmpPath.length() - 1); + + pos = tmpPath.rfind('/'); + if (string::npos != pos) + return tmpPath.substr(pos + 1); + + return tmpPath; +} + void InjectedBundlePage::willAddMessageToConsole(WKStringRef message, uint32_t lineNumber) { if (!InjectedBundle::shared().isTestRunning()) return; - // FIXME: Strip file: urls. - InjectedBundle::shared().os() << "CONSOLE MESSAGE: line " << lineNumber << ": " << message << "\n"; + string messageString = toSTD(message); + size_t fileProtocolStart = messageString.find("file://"); + if (fileProtocolStart != string::npos) + // FIXME: The code below does not handle additional text after url nor multiple urls. This matches DumpRenderTree implementation. + messageString = messageString.substr(0, fileProtocolStart) + lastFileURLPathComponent(messageString.substr(fileProtocolStart)); + + InjectedBundle::shared().os() << "CONSOLE MESSAGE: line " << lineNumber << ": " << messageString << "\n"; } void InjectedBundlePage::willSetStatusbarText(WKStringRef statusbarText) @@ -918,6 +1009,31 @@ void InjectedBundlePage::didChangeSelection(WKStringRef notificationName) InjectedBundle::shared().os() << "EDITING DELEGATE: webViewDidChangeSelection:" << notificationName << "\n"; } +#if ENABLE(FULLSCREEN_API) +bool InjectedBundlePage::supportsFullScreen(WKBundlePageRef pageRef, WKFullScreenKeyboardRequestType requestType) +{ + if (InjectedBundle::shared().layoutTestController()->shouldDumpFullScreenCallbacks()) + InjectedBundle::shared().os() << "supportsFullScreen() == true\n"; + return true; +} + +void InjectedBundlePage::enterFullScreenForElement(WKBundlePageRef pageRef, WKBundleNodeHandleRef elementRef) +{ + if (InjectedBundle::shared().layoutTestController()->shouldDumpFullScreenCallbacks()) + InjectedBundle::shared().os() << "enterFullScreenForElement()\n"; + WKBundlePageWillEnterFullScreen(pageRef); + WKBundlePageDidEnterFullScreen(pageRef); +} + +void InjectedBundlePage::exitFullScreenForElement(WKBundlePageRef pageRef, WKBundleNodeHandleRef elementRef) +{ + if (InjectedBundle::shared().layoutTestController()->shouldDumpFullScreenCallbacks()) + InjectedBundle::shared().os() << "exitFullScreenForElement()\n"; + WKBundlePageWillExitFullScreen(pageRef); + WKBundlePageDidExitFullScreen(pageRef); +} +#endif + static bool compareByTargetName(WKBundleBackForwardListItemRef item1, WKBundleBackForwardListItemRef item2) { return toSTD(adoptWK(WKBundleBackForwardListItemCopyTarget(item1))) < toSTD(adoptWK(WKBundleBackForwardListItemCopyTarget(item2))); diff --git a/Tools/WebKitTestRunner/InjectedBundle/InjectedBundlePage.h b/Tools/WebKitTestRunner/InjectedBundle/InjectedBundlePage.h index 2c3e9df..bc04e9a 100644 --- a/Tools/WebKitTestRunner/InjectedBundle/InjectedBundlePage.h +++ b/Tools/WebKitTestRunner/InjectedBundle/InjectedBundlePage.h @@ -94,6 +94,16 @@ private: void didFinishLoadForResource(WKBundlePageRef, WKBundleFrameRef, uint64_t identifier); void didFailLoadForResource(WKBundlePageRef, WKBundleFrameRef, uint64_t identifier, WKErrorRef); + // WKBundlePagePolicyClient + static WKBundlePagePolicyAction decidePolicyForNavigationAction(WKBundlePageRef, WKBundleFrameRef, WKBundleNavigationActionRef, WKURLRequestRef, WKTypeRef*, const void*); + static WKBundlePagePolicyAction decidePolicyForNewWindowAction(WKBundlePageRef, WKBundleFrameRef, WKBundleNavigationActionRef, WKURLRequestRef, WKStringRef frameName, WKTypeRef*, const void*); + static WKBundlePagePolicyAction decidePolicyForResponse(WKBundlePageRef, WKBundleFrameRef, WKURLResponseRef, WKURLRequestRef, WKTypeRef*, const void*); + static void unableToImplementPolicy(WKBundlePageRef, WKBundleFrameRef, WKErrorRef, WKTypeRef*, const void*); + WKBundlePagePolicyAction decidePolicyForNavigationAction(WKBundlePageRef, WKBundleFrameRef, WKBundleNavigationActionRef, WKURLRequestRef, WKTypeRef*); + WKBundlePagePolicyAction decidePolicyForNewWindowAction(WKBundlePageRef, WKBundleFrameRef, WKBundleNavigationActionRef, WKURLRequestRef, WKStringRef frameName, WKTypeRef*); + WKBundlePagePolicyAction decidePolicyForResponse(WKBundlePageRef, WKBundleFrameRef, WKURLResponseRef, WKURLRequestRef, WKTypeRef*); + void unableToImplementPolicy(WKBundlePageRef, WKBundleFrameRef, WKErrorRef, WKTypeRef*); + // UI Client static void willAddMessageToConsole(WKBundlePageRef, WKStringRef message, uint32_t lineNumber, const void* clientInfo); static void willSetStatusbarText(WKBundlePageRef, WKStringRef statusbarText, const void* clientInfo); @@ -106,6 +116,13 @@ private: void willRunJavaScriptConfirm(WKStringRef message, WKBundleFrameRef); void willRunJavaScriptPrompt(WKStringRef message, WKStringRef defaultValue, WKBundleFrameRef); +#if ENABLE(FULLSCREEN_API) + // Full Screen client + static bool supportsFullScreen(WKBundlePageRef, WKFullScreenKeyboardRequestType); + static void enterFullScreenForElement(WKBundlePageRef, WKBundleNodeHandleRef element); + static void exitFullScreenForElement(WKBundlePageRef, WKBundleNodeHandleRef element); +#endif + // Editor client static bool shouldBeginEditing(WKBundlePageRef, WKBundleRangeHandleRef, const void* clientInfo); static bool shouldEndEditing(WKBundlePageRef, WKBundleRangeHandleRef, const void* clientInfo); diff --git a/Tools/WebKitTestRunner/InjectedBundle/LayoutTestController.cpp b/Tools/WebKitTestRunner/InjectedBundle/LayoutTestController.cpp index 7c49d03..45725b4 100644 --- a/Tools/WebKitTestRunner/InjectedBundle/LayoutTestController.cpp +++ b/Tools/WebKitTestRunner/InjectedBundle/LayoutTestController.cpp @@ -29,14 +29,17 @@ #include "InjectedBundle.h" #include "InjectedBundlePage.h" #include "JSLayoutTestController.h" +#include "PlatformWebView.h" #include "StringFunctions.h" +#include "TestController.h" #include <WebKit2/WKBundleBackForwardList.h> #include <WebKit2/WKBundleFrame.h> #include <WebKit2/WKBundleFramePrivate.h> #include <WebKit2/WKBundleInspector.h> +#include <WebKit2/WKBundleNodeHandlePrivate.h> #include <WebKit2/WKBundlePagePrivate.h> -#include <WebKit2/WKBundleScriptWorld.h> #include <WebKit2/WKBundlePrivate.h> +#include <WebKit2/WKBundleScriptWorld.h> #include <WebKit2/WKRetainPtr.h> #include <WebKit2/WebKit2.h> #include <wtf/HashMap.h> @@ -96,6 +99,7 @@ LayoutTestController::LayoutTestController() , m_dumpStatusCallbacks(false) , m_dumpTitleChanges(false) , m_dumpPixels(true) + , m_dumpFullScreenCallbacks(false) , m_waitToDump(false) , m_testRepaint(false) , m_testRepaintSweepHorizontally(false) @@ -286,6 +290,16 @@ bool LayoutTestController::findString(JSStringRef target, JSValueRef optionsArra return WKBundlePageFindString(InjectedBundle::shared().page()->page(), toWK(target).get(), options); } +void LayoutTestController::clearAllDatabases() +{ + WKBundleClearAllDatabases(InjectedBundle::shared().bundle()); +} + +void LayoutTestController::setDatabaseQuota(uint64_t quota) +{ + return WKBundleSetDatabaseQuota(InjectedBundle::shared().bundle(), quota); +} + bool LayoutTestController::isCommandEnabled(JSStringRef name) { return WKBundlePageIsEditingCommandEnabled(InjectedBundle::shared().page()->page(), toWK(name).get()); @@ -307,11 +321,59 @@ void LayoutTestController::setAllowUniversalAccessFromFileURLs(bool enabled) WKBundleOverrideAllowUniversalAccessFromFileURLsForTestRunner(InjectedBundle::shared().bundle(), InjectedBundle::shared().pageGroup(), enabled); } +void LayoutTestController::setAllowFileAccessFromFileURLs(bool enabled) +{ + WKBundleSetAllowFileAccessFromFileURLs(InjectedBundle::shared().bundle(), InjectedBundle::shared().pageGroup(), enabled); +} + +int LayoutTestController::numberOfPages(double pageWidthInPixels, double pageHeightInPixels) +{ + WKBundleFrameRef mainFrame = WKBundlePageGetMainFrame(InjectedBundle::shared().page()->page()); + return WKBundleNumberOfPages(InjectedBundle::shared().bundle(), mainFrame, pageWidthInPixels, pageHeightInPixels); +} + +int LayoutTestController::pageNumberForElementById(JSStringRef id, double pageWidthInPixels, double pageHeightInPixels) +{ + WKBundleFrameRef mainFrame = WKBundlePageGetMainFrame(InjectedBundle::shared().page()->page()); + return WKBundlePageNumberForElementById(InjectedBundle::shared().bundle(), mainFrame, toWK(id).get(), pageWidthInPixels, pageHeightInPixels); +} + +JSRetainPtr<JSStringRef> LayoutTestController::pageSizeAndMarginsInPixels(int pageIndex, int width, int height, int marginTop, int marginRight, int marginBottom, int marginLeft) +{ + WKBundleFrameRef mainFrame = WKBundlePageGetMainFrame(InjectedBundle::shared().page()->page()); + return toJS(WKBundlePageSizeAndMarginsInPixels(InjectedBundle::shared().bundle(), mainFrame, pageIndex, width, height, marginTop, marginRight, marginBottom, marginLeft)); +} + +bool LayoutTestController::isPageBoxVisible(int pageIndex) +{ + WKBundleFrameRef mainFrame = WKBundlePageGetMainFrame(InjectedBundle::shared().page()->page()); + return WKBundleIsPageBoxVisible(InjectedBundle::shared().bundle(), mainFrame, pageIndex); +} + unsigned LayoutTestController::windowCount() { return InjectedBundle::shared().pageCount(); } +JSValueRef LayoutTestController::shadowRoot(JSValueRef element) +{ + WKBundleFrameRef mainFrame = WKBundlePageGetMainFrame(InjectedBundle::shared().page()->page()); + JSContextRef context = WKBundleFrameGetJavaScriptContext(mainFrame); + + if (!element || !JSValueIsObject(context, element)) + return JSValueMakeNull(context); + + WKRetainPtr<WKBundleNodeHandleRef> domElement = adoptWK(WKBundleNodeHandleCreate(context, const_cast<JSObjectRef>(element))); + if (!domElement) + return JSValueMakeNull(context); + + WKRetainPtr<WKBundleNodeHandleRef> shadowRootDOMElement = adoptWK(WKBundleNodeHandleCopyElementShadowRoot(domElement.get())); + if (!shadowRootDOMElement) + return JSValueMakeNull(context); + + return WKBundleFrameGetJavaScriptWrapperForNodeForWorld(mainFrame, shadowRootDOMElement.get(), WKBundleScriptWorldNormalWorld()); +} + void LayoutTestController::clearBackForwardList() { WKBundleBackForwardListClear(WKBundlePageGetBackForwardList(InjectedBundle::shared().page()->page())); diff --git a/Tools/WebKitTestRunner/InjectedBundle/LayoutTestController.h b/Tools/WebKitTestRunner/InjectedBundle/LayoutTestController.h index b37f102..00d7e57 100644 --- a/Tools/WebKitTestRunner/InjectedBundle/LayoutTestController.h +++ b/Tools/WebKitTestRunner/InjectedBundle/LayoutTestController.h @@ -67,6 +67,7 @@ public: void dumpSelectionRect() { } // Will need to do something when we support pixel tests. void dumpStatusCallbacks() { m_dumpStatusCallbacks = true; } void dumpTitleChanges() { m_dumpTitleChanges = true; } + void dumpFullScreenCallbacks() { m_dumpFullScreenCallbacks = true; } // Special options. void keepWebHistory(); @@ -75,6 +76,7 @@ public: void setCloseRemainingWindowsWhenComplete(bool value) { m_shouldCloseExtraWindows = value; } void setXSSAuditorEnabled(bool); void setAllowUniversalAccessFromFileURLs(bool); + void setAllowFileAccessFromFileURLs(bool); // Special DOM functions. JSValueRef computedStyleIncludingVisitedInfo(JSValueRef element); @@ -84,6 +86,7 @@ public: bool isCommandEnabled(JSStringRef name); JSRetainPtr<JSStringRef> markerTextForListItem(JSValueRef element); unsigned windowCount(); + JSValueRef shadowRoot(JSValueRef element); // Repaint testing. void testRepaint() { m_testRepaint = true; } @@ -106,6 +109,17 @@ public: // Text search testing. bool findString(JSStringRef, JSValueRef optionsArray); + // Local storage + void clearAllDatabases(); + void setDatabaseQuota(uint64_t); + JSRetainPtr<JSStringRef> pathToLocalResource(JSStringRef); + + // Printing + int numberOfPages(double pageWidthInPixels, double pageHeightInPixels); + int pageNumberForElementById(JSStringRef, double pageWidthInPixels, double pageHeightInPixels); + JSRetainPtr<JSStringRef> pageSizeAndMarginsInPixels(int pageIndex, int width, int height, int marginTop, int marginRight, int marginBottom, int marginLeft); + bool isPageBoxVisible(int pageIndex); + enum WhatToDump { RenderTree, MainFrameText, AllFramesText }; WhatToDump whatToDump() const { return m_whatToDump; } @@ -116,6 +130,7 @@ public: bool shouldDumpStatusCallbacks() const { return m_dumpStatusCallbacks; } bool shouldDumpTitleChanges() const { return m_dumpTitleChanges; } bool shouldDumpPixels() const { return m_dumpPixels; } + bool shouldDumpFullScreenCallbacks() const { return m_dumpFullScreenCallbacks; } bool waitToDump() const { return m_waitToDump; } void waitToDumpWatchdogTimerFired(); @@ -157,6 +172,7 @@ private: bool m_dumpStatusCallbacks; bool m_dumpTitleChanges; bool m_dumpPixels; + bool m_dumpFullScreenCallbacks; bool m_waitToDump; // True if waitUntilDone() has been called, but notifyDone() has not yet been called. bool m_testRepaint; bool m_testRepaintSweepHorizontally; diff --git a/Tools/WebKitTestRunner/InjectedBundle/mac/LayoutTestControllerMac.mm b/Tools/WebKitTestRunner/InjectedBundle/mac/LayoutTestControllerMac.mm index 2eb4d5b..1d5d008 100644 --- a/Tools/WebKitTestRunner/InjectedBundle/mac/LayoutTestControllerMac.mm +++ b/Tools/WebKitTestRunner/InjectedBundle/mac/LayoutTestControllerMac.mm @@ -56,4 +56,9 @@ void LayoutTestController::initializeWaitToDumpWatchdogTimerIfNeeded() CFRunLoopAddTimer(CFRunLoopGetCurrent(), m_waitToDumpWatchdogTimer.get(), kCFRunLoopCommonModes); } +JSRetainPtr<JSStringRef> LayoutTestController::pathToLocalResource(JSStringRef url) +{ + return JSStringRetain(url); // Do nothing on mac. +} + } // namespace WTR diff --git a/Tools/WebKitTestRunner/InjectedBundle/qt/InjectedBundle.pro b/Tools/WebKitTestRunner/InjectedBundle/qt/InjectedBundle.pro index 6838205..0bac510 100644 --- a/Tools/WebKitTestRunner/InjectedBundle/qt/InjectedBundle.pro +++ b/Tools/WebKitTestRunner/InjectedBundle/qt/InjectedBundle.pro @@ -72,7 +72,7 @@ INCLUDEPATH = \ PREFIX_HEADER = $$PWD/../../WebKitTestRunnerPrefix.h *-g++*:QMAKE_CXXFLAGS += "-include $$PREFIX_HEADER" -unix:!mac:!symbian { +unix:!mac:!symbian:!embedded { CONFIG += link_pkgconfig PKGCONFIG += fontconfig } @@ -80,3 +80,6 @@ unix:!mac:!symbian { TARGET = WTRInjectedBundle DESTDIR = $$OUTPUT_DIR/lib !CONFIG(standalone_package): CONFIG -= app_bundle +linux-* { + QMAKE_LFLAGS += -Wl,--no-undefined +} diff --git a/Tools/WebKitTestRunner/InjectedBundle/qt/LayoutTestControllerQt.cpp b/Tools/WebKitTestRunner/InjectedBundle/qt/LayoutTestControllerQt.cpp index 91f49ea..72902e1 100644 --- a/Tools/WebKitTestRunner/InjectedBundle/qt/LayoutTestControllerQt.cpp +++ b/Tools/WebKitTestRunner/InjectedBundle/qt/LayoutTestControllerQt.cpp @@ -28,6 +28,7 @@ #include "LayoutTestController.h" #include "InjectedBundle.h" +#include <QDir> #include <QObject> namespace WTR { @@ -70,6 +71,12 @@ void LayoutTestController::initializeWaitToDumpWatchdogTimerIfNeeded() m_waitToDumpWatchdogTimer.start(waitToDumpWatchdogTimerInterval * 1000); } +JSRetainPtr<JSStringRef> LayoutTestController::pathToLocalResource(JSStringRef url) +{ + QString path = QDir::toNativeSeparators(QString(reinterpret_cast<const QChar*>(JSStringGetCharactersPtr(url)), JSStringGetLength(url))); + return JSStringCreateWithCharacters(reinterpret_cast<const JSChar*>(path.constData()), path.length()); +} + } // namespace WTR #include "LayoutTestControllerQt.moc" diff --git a/Tools/WebKitTestRunner/InjectedBundle/win/LayoutTestControllerWin.cpp b/Tools/WebKitTestRunner/InjectedBundle/win/LayoutTestControllerWin.cpp index 7c500f2..88230c4 100644 --- a/Tools/WebKitTestRunner/InjectedBundle/win/LayoutTestControllerWin.cpp +++ b/Tools/WebKitTestRunner/InjectedBundle/win/LayoutTestControllerWin.cpp @@ -59,4 +59,9 @@ void LayoutTestController::initializeWaitToDumpWatchdogTimerIfNeeded() m_waitToDumpWatchdogTimer = ::SetTimer(0, waitToDumpWatchdogTimerIdentifier, waitToDumpWatchdogTimerInterval * 1000, WTR::waitToDumpWatchdogTimerFired); } +JSRetainPtr<JSStringRef> LayoutTestController::pathToLocalResource(JSStringRef url) +{ + return JSStringRetain(url); // TODO. +} + } // namespace WTR diff --git a/Tools/WebKitTestRunner/StringFunctions.h b/Tools/WebKitTestRunner/StringFunctions.h index 33e391d..28c6f85 100644 --- a/Tools/WebKitTestRunner/StringFunctions.h +++ b/Tools/WebKitTestRunner/StringFunctions.h @@ -44,11 +44,6 @@ namespace WTR { // Conversion functions -template<typename T> static inline WKRetainPtr<T> adoptWK(const T item) -{ - return WKRetainPtr<T>(AdoptWK, item); -} - inline WKRetainPtr<WKStringRef> toWK(JSStringRef string) { return adoptWK(WKStringCreateWithJSString(string)); diff --git a/Tools/WebKitTestRunner/TestController.cpp b/Tools/WebKitTestRunner/TestController.cpp index 42331da..d33200f 100644 --- a/Tools/WebKitTestRunner/TestController.cpp +++ b/Tools/WebKitTestRunner/TestController.cpp @@ -139,6 +139,9 @@ WKPageRef TestController::createOtherPage(WKPageRef oldPage, WKDictionaryRef, WK createOtherPage, 0, // showPage closeOtherPage, + 0, // takeFocus + 0, // focus + 0, // unfocus 0, // runJavaScriptAlert 0, // runJavaScriptConfirm 0, // runJavaScriptPrompt @@ -273,6 +276,9 @@ void TestController::initialize(int argc, const char* argv[]) createOtherPage, 0, // showPage 0, // close + 0, // takeFocus + 0, // focus + 0, // unfocus 0, // runJavaScriptAlert 0, // runJavaScriptConfirm 0, // runJavaScriptPrompt @@ -358,6 +364,9 @@ bool TestController::resetStateToConsistentValues() WKPreferencesSetDOMPasteAllowed(preferences, true); WKPreferencesSetUniversalAccessFromFileURLsAllowed(preferences, true); WKPreferencesSetFileAccessFromFileURLsAllowed(preferences, true); +#if ENABLE(FULLSCREEN_API) + WKPreferencesSetFullScreenEnabled(preferences, true); +#endif static WKStringRef standardFontFamily = WKStringCreateWithUTF8CString("Times"); static WKStringRef cursiveFontFamily = WKStringCreateWithUTF8CString("Apple Chancery"); diff --git a/Tools/WebKitTestRunner/config.h b/Tools/WebKitTestRunner/config.h index 81f8066..38568ae 100644 --- a/Tools/WebKitTestRunner/config.h +++ b/Tools/WebKitTestRunner/config.h @@ -49,18 +49,18 @@ #define WEBKIT_EXPORTDATA #endif -#define WTF_EXPORT_PRIVATE JS_EXPORTDATA -#define JS_EXPORT_PRIVATE JS_EXPORTDATA +#define WTF_EXPORT_PRIVATE +#define JS_EXPORT_PRIVATE #endif /* USE(EXPORT_MACROS) */ #if PLATFORM(WIN) #define WTF_USE_CF 1 #if defined(WIN_CAIRO) -#define WTF_PLATFORM_CAIRO 1 +#define WTF_USE_CAIRO 1 #define WTF_USE_CURL 1 #else -#define WTF_PLATFORM_CG 1 +#define WTF_USE_CG 1 #define WTF_USE_CFNETWORK 1 #endif #endif diff --git a/Tools/WebKitTestRunner/qt/WebKitTestRunner.pro b/Tools/WebKitTestRunner/qt/WebKitTestRunner.pro index 684a14a..eb6602f 100644 --- a/Tools/WebKitTestRunner/qt/WebKitTestRunner.pro +++ b/Tools/WebKitTestRunner/qt/WebKitTestRunner.pro @@ -26,7 +26,7 @@ INCLUDEPATH += \ DESTDIR = $$OUTPUT_DIR/bin -unix:!mac:!symbian { +unix:!mac:!symbian:!embedded { CONFIG += link_pkgconfig PKGCONFIG += fontconfig } @@ -57,7 +57,7 @@ linux-* { QMAKE_RPATHDIR = \$\$ORIGIN/../lib $$QMAKE_RPATHDIR MY_RPATH = $$join(QMAKE_RPATHDIR, ":") - QMAKE_LFLAGS += -Wl,-z,origin \'-Wl,-rpath,$${MY_RPATH}\' + QMAKE_LFLAGS += -Wl,-z,origin \'-Wl,-rpath,$${MY_RPATH}\' -Wl,--no-undefined QMAKE_RPATHDIR = } else { QMAKE_RPATHDIR = $$OUTPUT_DIR/lib $$QMAKE_RPATHDIR diff --git a/Tools/WebKitTestRunner/win/InjectedBundleProduction.vsprops b/Tools/WebKitTestRunner/win/InjectedBundleProduction.vsprops index b036c84..a8e0607 100644 --- a/Tools/WebKitTestRunner/win/InjectedBundleProduction.vsprops +++ b/Tools/WebKitTestRunner/win/InjectedBundleProduction.vsprops @@ -5,7 +5,7 @@ Name="InjectedBundleProduction" InheritedPropertySheets=" $(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\common.vsprops; - $(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\release.vsprops; + $(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\releaseproduction.vsprops; $(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\production.vsprops; ..\Configurations\InjectedBundleCoreFoundation.vsprops; ..\Configurations\InjectedBundleCommon.vsprops" diff --git a/Tools/WebKitTestRunner/win/InjectedBundleRelease.vsprops b/Tools/WebKitTestRunner/win/InjectedBundleRelease.vsprops index 8f65ff3..8c88cf8 100644 --- a/Tools/WebKitTestRunner/win/InjectedBundleRelease.vsprops +++ b/Tools/WebKitTestRunner/win/InjectedBundleRelease.vsprops @@ -5,6 +5,7 @@ Name="InjectedBundleRelease" InheritedPropertySheets=" $(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\common.vsprops; + $(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\releaseproduction.vsprops; $(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\release.vsprops; ..\Configurations\InjectedBundleCoreFoundation.vsprops; ..\Configurations\InjectedBundleCommon.vsprops" diff --git a/Tools/WebKitTestRunner/win/InjectedBundleReleaseCairoCFLite.vsprops b/Tools/WebKitTestRunner/win/InjectedBundleReleaseCairoCFLite.vsprops index c7dfb84..22fddd3 100644 --- a/Tools/WebKitTestRunner/win/InjectedBundleReleaseCairoCFLite.vsprops +++ b/Tools/WebKitTestRunner/win/InjectedBundleReleaseCairoCFLite.vsprops @@ -5,6 +5,7 @@ Name="InjectedBundleReleaseCairoCFLite" InheritedPropertySheets=" $(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\common.vsprops; + $(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\releaseproduction.vsprops; $(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\release.vsprops; $(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\WinCairo.vsprops; ..\Configurations\InjectedBundleCFLite.vsprops; diff --git a/Tools/WebKitTestRunner/win/TestInvocationWin.cpp b/Tools/WebKitTestRunner/win/TestInvocationWin.cpp index 7c79ff5..2aec9ae 100644 --- a/Tools/WebKitTestRunner/win/TestInvocationWin.cpp +++ b/Tools/WebKitTestRunner/win/TestInvocationWin.cpp @@ -28,7 +28,7 @@ namespace WTR { -#if !PLATFORM(CG) +#if !USE(CG) && !USE(CAIRO) void TestInvocation::dumpPixelsAndCompareWithExpected(WKImageRef) { } diff --git a/Tools/WebKitTestRunner/win/WebKitTestRunnerProduction.vsprops b/Tools/WebKitTestRunner/win/WebKitTestRunnerProduction.vsprops index 28dbf04..c11c3ff 100644 --- a/Tools/WebKitTestRunner/win/WebKitTestRunnerProduction.vsprops +++ b/Tools/WebKitTestRunner/win/WebKitTestRunnerProduction.vsprops @@ -5,7 +5,7 @@ Name="WebKitTestRunnerProduction" InheritedPropertySheets=" $(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\common.vsprops; - $(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\release.vsprops; + $(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\releaseproduction.vsprops; $(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\production.vsprops; ..\Configurations\WebKitTestRunnerCommon.vsprops; ..\Configurations\WebKitTestRunnerCoreFoundation.vsprops; diff --git a/Tools/WebKitTestRunner/win/WebKitTestRunnerRelease.vsprops b/Tools/WebKitTestRunner/win/WebKitTestRunnerRelease.vsprops index 788f4ef..1987a61 100644 --- a/Tools/WebKitTestRunner/win/WebKitTestRunnerRelease.vsprops +++ b/Tools/WebKitTestRunner/win/WebKitTestRunnerRelease.vsprops @@ -5,6 +5,7 @@ Name="WebKitTestRunnerRelease" InheritedPropertySheets=" $(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\common.vsprops; + $(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\releaseproduction.vsprops; $(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\release.vsprops; ..\Configurations\WebKitTestRunnerCommon.vsprops; ..\Configurations\WebKitTestRunnerCoreFoundation.vsprops; diff --git a/Tools/WebKitTestRunner/win/WebKitTestRunnerReleaseCairoCFLite.vsprops b/Tools/WebKitTestRunner/win/WebKitTestRunnerReleaseCairoCFLite.vsprops index f6e0f00..c5a73a5 100644 --- a/Tools/WebKitTestRunner/win/WebKitTestRunnerReleaseCairoCFLite.vsprops +++ b/Tools/WebKitTestRunner/win/WebKitTestRunnerReleaseCairoCFLite.vsprops @@ -5,6 +5,7 @@ Name="WebKitTestRunnerReleaseCairoCFLite" InheritedPropertySheets=" $(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\common.vsprops; + $(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\releaseproduction.vsprops; $(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\release.vsprops; $(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\WinCairo.vsprops; ..\Configurations\WebKitTestRunnerCommon.vsprops; diff --git a/Tools/WinLauncher/PrintWebUIDelegate.cpp b/Tools/WinLauncher/PrintWebUIDelegate.cpp index ccc267b..3e92144 100644 --- a/Tools/WinLauncher/PrintWebUIDelegate.cpp +++ b/Tools/WinLauncher/PrintWebUIDelegate.cpp @@ -27,14 +27,13 @@ #include "stdafx.h" #include "PrintWebUIDelegate.h" +#include <WebKit/WebKitCOMAPI.h> #include <commctrl.h> #include <commdlg.h> #include <objbase.h> #include <shlwapi.h> #include <wininet.h> -#include <WebKit/WebKitCOMAPI.h> - static const int MARGIN = 20; HRESULT PrintWebUIDelegate::QueryInterface(REFIID riid, void** ppvObject) @@ -97,98 +96,98 @@ HRESULT PrintWebUIDelegate::webViewPrintingMarginRect(IWebView* view, RECT* rect HRESULT PrintWebUIDelegate::webViewHeaderHeight(IWebView* webView, float* height) { - if (!webView || !height) - return E_POINTER; - - HDC dc = ::GetDC(0); + if (!webView || !height) + return E_POINTER; - TEXTMETRIC textMetric; - ::GetTextMetrics(dc, &textMetric); - ::ReleaseDC(0, dc); + HDC dc = ::GetDC(0); - *height = 1.1 * textMetric.tmHeight; + TEXTMETRIC textMetric; + ::GetTextMetrics(dc, &textMetric); + ::ReleaseDC(0, dc); + + *height = 1.1 * textMetric.tmHeight; - return S_OK; + return S_OK; } HRESULT PrintWebUIDelegate::webViewFooterHeight(IWebView* webView, float* height) { - if (!webView || !height) - return E_POINTER; + if (!webView || !height) + return E_POINTER; - HDC dc = ::GetDC(0); + HDC dc = ::GetDC(0); - TEXTMETRIC textMetric; - ::GetTextMetrics(dc, &textMetric); - ::ReleaseDC(0, dc); + TEXTMETRIC textMetric; + ::GetTextMetrics(dc, &textMetric); + ::ReleaseDC(0, dc); - *height = 1.1 * textMetric.tmHeight; + *height = 1.1 * textMetric.tmHeight; - return S_OK; + return S_OK; } -HRESULT PrintWebUIDelegate::drawHeaderInRect( - /* [in] */ IWebView *webView, - /* [in] */ RECT *rect, +HRESULT PrintWebUIDelegate::drawHeaderInRect( + /* [in] */ IWebView* webView, + /* [in] */ RECT* rect, /* [in] */ OLE_HANDLE drawingContext) { - if (!webView || !rect) - return E_POINTER; + if (!webView || !rect) + return E_POINTER; - // Turn off header for now. - HDC dc = reinterpret_cast<HDC>(drawingContext); + // Turn off header for now. + HDC dc = reinterpret_cast<HDC>(drawingContext); - HFONT hFont = (HFONT)::GetStockObject(ANSI_VAR_FONT); - HFONT hOldFont = (HFONT)::SelectObject(dc, hFont); + HGDIOBJ hFont = ::GetStockObject(ANSI_VAR_FONT); + HGDIOBJ hOldFont = ::SelectObject(dc, hFont); - LPCTSTR header(_T("[Sample Header]")); - int length = _tcslen(header); + LPCWSTR header = L"[Sample Header]"; + size_t length = wcslen(header); - int rc = ::DrawText(dc, header, length, rect, DT_LEFT | DT_NOCLIP | DT_VCENTER | DT_SINGLELINE); - ::SelectObject(dc, hOldFont); + int rc = ::DrawTextW(dc, header, length, rect, DT_LEFT | DT_NOCLIP | DT_VCENTER | DT_SINGLELINE); + ::SelectObject(dc, hOldFont); - if (!rc) - return E_FAIL; + if (!rc) + return E_FAIL; - ::MoveToEx(dc, rect->left, rect->bottom, 0); - HPEN hPen = (HPEN)::GetStockObject(BLACK_PEN); - HPEN hOldPen = (HPEN)::SelectObject(dc, hPen); - ::LineTo(dc, rect->right, rect->bottom); - ::SelectObject(dc, hOldPen); + ::MoveToEx(dc, rect->left, rect->bottom, 0); + HGDIOBJ hPen = ::GetStockObject(BLACK_PEN); + HGDIOBJ hOldPen = ::SelectObject(dc, hPen); + ::LineTo(dc, rect->right, rect->bottom); + ::SelectObject(dc, hOldPen); - return S_OK; + return S_OK; } -HRESULT PrintWebUIDelegate::drawFooterInRect( - /* [in] */ IWebView *webView, - /* [in] */ RECT *rect, +HRESULT PrintWebUIDelegate::drawFooterInRect( + /* [in] */ IWebView* webView, + /* [in] */ RECT* rect, /* [in] */ OLE_HANDLE drawingContext, /* [in] */ UINT pageIndex, /* [in] */ UINT pageCount) { - if (!webView || !rect) - return E_POINTER; + if (!webView || !rect) + return E_POINTER; - HDC dc = reinterpret_cast<HDC>(drawingContext); + HDC dc = reinterpret_cast<HDC>(drawingContext); - HFONT hFont = (HFONT)::GetStockObject(ANSI_VAR_FONT); - HFONT hOldFont = (HFONT)::SelectObject(dc, hFont); + HGDIOBJ hFont = ::GetStockObject(ANSI_VAR_FONT); + HGDIOBJ hOldFont = ::SelectObject(dc, hFont); - LPCTSTR footer(_T("[Sample Footer]")); - int length = _tcslen(footer); + LPCWSTR footer = L"[Sample Footer]"; + size_t length = wcslen(footer); - // Add a line, 1/10th inch above the footer text from left margin to right margin. - ::MoveToEx(dc, rect->left, rect->top, 0); - HPEN hPen = (HPEN)::GetStockObject(BLACK_PEN); - HPEN hOldPen = (HPEN)::SelectObject(dc, hPen); - ::LineTo(dc, rect->right, rect->top); - ::SelectObject(dc, hOldPen); + // Add a line, 1/10th inch above the footer text from left margin to right margin. + ::MoveToEx(dc, rect->left, rect->top, 0); + HGDIOBJ hPen = ::GetStockObject(BLACK_PEN); + HGDIOBJ hOldPen = ::SelectObject(dc, hPen); + ::LineTo(dc, rect->right, rect->top); + ::SelectObject(dc, hOldPen); - int rc = ::DrawText(dc, footer, length, rect, DT_LEFT | DT_NOCLIP | DT_VCENTER | DT_SINGLELINE); - ::SelectObject(dc, hOldFont); + int rc = ::DrawTextW(dc, footer, length, rect, DT_LEFT | DT_NOCLIP | DT_VCENTER | DT_SINGLELINE); + ::SelectObject(dc, hOldFont); - if (!rc) - return E_FAIL; + if (!rc) + return E_FAIL; - return S_OK; + return S_OK; } diff --git a/Tools/WinLauncher/WinLauncher.cpp b/Tools/WinLauncher/WinLauncher.cpp index 5caf230..f572b15 100644 --- a/Tools/WinLauncher/WinLauncher.cpp +++ b/Tools/WinLauncher/WinLauncher.cpp @@ -327,12 +327,12 @@ void PrintView(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { HDC printDC = getPrinterDC(); if (!printDC) { - ::MessageBox(0, _T("Error creating printing DC"), _T("Error"), MB_APPLMODAL | MB_OK); + ::MessageBoxW(0, L"Error creating printing DC", L"Error", MB_APPLMODAL | MB_OK); return; } if (::SetAbortProc(printDC, AbortProc) == SP_ERROR) { - ::MessageBox(0, _T("Error setting up AbortProc"), _T("Error"), MB_APPLMODAL | MB_OK); + ::MessageBoxW(0, L"Error setting up AbortProc", L"Error", MB_APPLMODAL | MB_OK); return; } @@ -350,7 +350,7 @@ void PrintView(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) framePrivate->getPrintedPageCount(printDC, &pageCount); DOCINFO di; - initDocStruct(&di, _T("WebKit Doc")); + initDocStruct(&di, L"WebKit Doc"); ::StartDoc(printDC, &di); // FIXME: Need CoreGraphics implementation diff --git a/Tools/WinLauncher/WinLauncherProduction.vsprops b/Tools/WinLauncher/WinLauncherProduction.vsprops index 83292fe..1069f4a 100644 --- a/Tools/WinLauncher/WinLauncherProduction.vsprops +++ b/Tools/WinLauncher/WinLauncherProduction.vsprops @@ -5,7 +5,7 @@ Name="WinLauncherProduction" InheritedPropertySheets=" $(WebKitVSPropsRedirectionDir)..\..\WebKitLibraries\win\tools\vsprops\common.vsprops; - $(WebKitVSPropsRedirectionDir)..\..\WebKitLibraries\win\tools\vsprops\release.vsprops; + $(WebKitVSPropsRedirectionDir)..\..\WebKitLibraries\win\tools\vsprops\releaseproduction.vsprops; $(WebKitVSPropsRedirectionDir)..\..\WebKitLibraries\win\tools\vsprops\production.vsprops; .\WinLauncherCommon.vsprops" > diff --git a/Tools/WinLauncher/WinLauncherRelease.vsprops b/Tools/WinLauncher/WinLauncherRelease.vsprops index 2b41482..8639931 100644 --- a/Tools/WinLauncher/WinLauncherRelease.vsprops +++ b/Tools/WinLauncher/WinLauncherRelease.vsprops @@ -5,6 +5,7 @@ Name="WinLauncherRelease" InheritedPropertySheets=" $(WebKitVSPropsRedirectionDir)..\..\WebKitLibraries\win\tools\vsprops\common.vsprops; + $(WebKitVSPropsRedirectionDir)..\..\WebKitLibraries\win\tools\vsprops\releaseproduction.vsprops; $(WebKitVSPropsRedirectionDir)..\..\WebKitLibraries\win\tools\vsprops\release.vsprops; .\WinLauncherCommon.vsprops" > diff --git a/Tools/WinLauncher/WinLauncherReleaseCairoCFLite.vsprops b/Tools/WinLauncher/WinLauncherReleaseCairoCFLite.vsprops index 351ac49..58aef68 100644 --- a/Tools/WinLauncher/WinLauncherReleaseCairoCFLite.vsprops +++ b/Tools/WinLauncher/WinLauncherReleaseCairoCFLite.vsprops @@ -5,6 +5,7 @@ Name="WinLauncherReleaseCairoCFLite" InheritedPropertySheets=" $(WebKitVSPropsRedirectionDir)..\..\WebKitLibraries\win\tools\vsprops\common.vsprops; + $(WebKitVSPropsRedirectionDir)..\..\WebKitLibraries\win\tools\vsprops\releaseproduction.vsprops; $(WebKitVSPropsRedirectionDir)..\..\WebKitLibraries\win\tools\vsprops\release.vsprops; $(WebKitVSPropsRedirectionDir)..\..\WebKitLibraries\win\tools\vsprops\WinCairo.vsprops; .\WinLauncherCommon.vsprops" diff --git a/Tools/record-memory-win/record-memory-winProduction.vsprops b/Tools/record-memory-win/record-memory-winProduction.vsprops index 4eb90f4..c8520f9 100644 --- a/Tools/record-memory-win/record-memory-winProduction.vsprops +++ b/Tools/record-memory-win/record-memory-winProduction.vsprops @@ -5,7 +5,7 @@ Name="record-memory-winProduction" InheritedPropertySheets=" $(WebKitVSPropsRedirectionDir)..\..\WebKitLibraries\win\tools\vsprops\common.vsprops; - $(WebKitVSPropsRedirectionDir)..\..\WebKitLibraries\win\tools\vsprops\release.vsprops; + $(WebKitVSPropsRedirectionDir)..\..\WebKitLibraries\win\tools\vsprops\releaseproduction.vsprops; $(WebKitVSPropsRedirectionDir)..\..\WebKitLibraries\win\tools\vsprops\production.vsprops; .\record-memory-win-common.vsprops" > diff --git a/Tools/record-memory-win/record-memory-winRelease.vsprops b/Tools/record-memory-win/record-memory-winRelease.vsprops index f38d7d7..1f43758 100644 --- a/Tools/record-memory-win/record-memory-winRelease.vsprops +++ b/Tools/record-memory-win/record-memory-winRelease.vsprops @@ -5,6 +5,7 @@ Name="record-memory-winRelease" InheritedPropertySheets=" $(WebKitVSPropsRedirectionDir)..\..\WebKitLibraries\win\tools\vsprops\common.vsprops; + $(WebKitVSPropsRedirectionDir)..\..\WebKitLibraries\win\tools\vsprops\releaseproduction.vsprops; $(WebKitVSPropsRedirectionDir)..\..\WebKitLibraries\win\tools\vsprops\release.vsprops; .\record-memory-win-common.vsprops" > diff --git a/Tools/record-memory-win/record-memory-winReleaseCairoCFLite.vsprops b/Tools/record-memory-win/record-memory-winReleaseCairoCFLite.vsprops index 8ce466f..8de269c 100644 --- a/Tools/record-memory-win/record-memory-winReleaseCairoCFLite.vsprops +++ b/Tools/record-memory-win/record-memory-winReleaseCairoCFLite.vsprops @@ -5,6 +5,7 @@ Name="record-memory-winReleaseCairoCFLite" InheritedPropertySheets=" $(WebKitVSPropsRedirectionDir)..\..\WebKitLibraries\win\tools\vsprops\common.vsprops; + $(WebKitVSPropsRedirectionDir)..\..\WebKitLibraries\win\tools\vsprops\releaseproduction.vsprops; $(WebKitVSPropsRedirectionDir)..\..\WebKitLibraries\win\tools\vsprops\release.vsprops; $(WebKitVSPropsRedirectionDir)..\..\WebKitLibraries\win\tools\vsprops\WinCairo.vsprops; .\record-memory-win-common.vsprops" diff --git a/Tools/wx/build/settings.py b/Tools/wx/build/settings.py index 6d7a7a5..8186d16 100644 --- a/Tools/wx/build/settings.py +++ b/Tools/wx/build/settings.py @@ -83,6 +83,7 @@ jscore_dirs = [ 'bytecompiler', 'debugger', 'DerivedSources', + 'heap', 'interpreter', 'jit', 'parser', diff --git a/Tools/wx/build/wxpresets.py b/Tools/wx/build/wxpresets.py index 3d6b693..f5181b1 100644 --- a/Tools/wx/build/wxpresets.py +++ b/Tools/wx/build/wxpresets.py @@ -53,8 +53,12 @@ def get_wx_version(wx_root): majorVersion = re.search("#define\swxMAJOR_VERSION\s+(\d+)", versionText).group(1) minorVersion = re.search("#define\swxMINOR_VERSION\s+(\d+)", versionText).group(1) + releaseVersion = re.search("#define\swxRELEASE_NUMBER\s+(\d+)", versionText).group(1) - return (majorVersion, minorVersion) + release = [majorVersion, minorVersion] + if int(minorVersion) % 2 == 1: + release.append(releaseVersion) + return release def get_wxmsw_settings(wx_root, shared = False, unicode = False, debug = False, wxPython=False): if not os.path.exists(wx_root): @@ -71,7 +75,7 @@ def get_wxmsw_settings(wx_root, shared = False, unicode = False, debug = False, ext = '' postfix = 'vc' - version_str_nodot = ''.join(get_wx_version(wx_root)) + version_str_nodot = ''.join(get_wx_version(wx_root)[0:2]) if shared: defines.append('WXUSINGDLL') @@ -84,7 +88,7 @@ def get_wxmsw_settings(wx_root, shared = False, unicode = False, debug = False, ext += 'u' depext = '' - if wxPython: + if wxPython and not version_str_nodot.startswith('29'): ext += 'h' depext += 'h' elif debug: diff --git a/Tools/wx/install-unix-extras b/Tools/wx/install-unix-extras index 00c936c..1f14294 100755 --- a/Tools/wx/install-unix-extras +++ b/Tools/wx/install-unix-extras @@ -80,6 +80,18 @@ LIBCURL_URL="http://curl.haxx.se/download/$LIBCURL_TARBALL" export MAC_OS_X_DEPLOYMENT_TARGET=10.4 +ARCH_FLAGS="-arch i386 -arch ppc -arch x86_64" +SDK="/Developer/SDKs/MacOSX10.4u.sdk" + +if [ ! -d $SDK ]; then + SDK="/Developer/SDKs/MacOSX10.5.sdk" +fi + +if [ "${OSTYPE:0:6}" == "darwin" ]; then + export CC="gcc-4.0" + export CXX="g++-4.0" +fi + cd $DL_DIR # build ICU if [ `which icu-config >/dev/null 2>&1` ]; then @@ -92,8 +104,8 @@ if [ `which icu-config >/dev/null 2>&1` ]; then if [ "${OSTYPE:0:6}" == "darwin" ]; then ./configure --prefix=$DEPS_PREFIX --disable-dependency-tracking - make CFLAGS="-O -g -isysroot /Developer/SDKs/MacOSX10.4u.sdk -arch i386 -arch ppc" \ - LDFLAGS="-arch i386 -arch ppc" + make CFLAGS="-O -g -isysroot $SDK $ARCH_FLAGS" \ + LDFLAGS=$ARCH_FLAGS make install else ./configure --prefix=$DEPS_PREFIX @@ -115,8 +127,8 @@ if [ ! -f $DEPS_PREFIX/lib/libiconv.$DLLEXT ]; then if [ "${OSTYPE:0:6}" == "darwin" ]; then ./configure --prefix=$DEPS_PREFIX --disable-dependency-tracking - make CFLAGS="-O -g -isysroot /Developer/SDKs/MacOSX10.4u.sdk -arch i386 -arch ppc" \ - LDFLAGS="-arch i386 -arch ppc" + make CFLAGS="-O -g -isysroot $SDK $ARCH_FLAGS" \ + LDFLAGS="$ARCH_FLAGS" make install else ./configure --prefix=$DEPS_PREFIX @@ -139,8 +151,8 @@ if [ ! -f $DEPS_PREFIX/lib/libjpeg.a ]; then if [ "${OSTYPE:0:6}" == "darwin" ]; then ./configure --prefix=$DEPS_PREFIX --disable-dependency-tracking - make CFLAGS="-O -g -isysroot /Developer/SDKs/MacOSX10.4u.sdk -arch i386 -arch ppc" \ - LDFLAGS="-arch i386 -arch ppc" + make CFLAGS="-O -g -isysroot $SDK $ARCH_FLAGS" \ + LDFLAGS="$ARCH_FLAGS" make install else ./configure --prefix=$DEPS_PREFIX @@ -163,8 +175,8 @@ if [ ! -f $DEPS_PREFIX/lib/libpng.a ]; then if [ "${OSTYPE:0:6}" == "darwin" ]; then ./configure --prefix=$DEPS_PREFIX --disable-dependency-tracking - make CFLAGS="-O -g -isysroot /Developer/SDKs/MacOSX10.4u.sdk -arch i386 -arch ppc" \ - LDFLAGS="-arch i386 -arch ppc" + make CFLAGS="-O -g -isysroot $SDK $ARCH_FLAGS" \ + LDFLAGS="$ARCH_FLAGS" make install else ./configure --prefix=$DEPS_PREFIX @@ -184,9 +196,40 @@ if [ ! -f $DEPS_PREFIX/lib/libcurl.$DLLEXT ]; then cd $DL_DIR/curl-$LIBCURL_VERSION if [ "${OSTYPE:0:6}" == "darwin" ]; then + # CURL creates different build headers for 32 and 64 bit, so to get a universal build, + # we must first create a 32 bit version of the header, then a 64 bit version, and + # have the original header simply decide which to use. + export CFLAGS="-O -g -isysroot $SDK -mmacosx-version-min=10.4 -arch i386 -arch ppc" + ./configure --prefix=$DEPS_PREFIX --disable-dependency-tracking + + mkdir -p $DEPS_PREFIX/include/curl + + cp include/curl/curlbuild.h include/curl/curlbuild32.h + cp include/curl/curlbuild.h $DEPS_PREFIX/include/curl/curlbuild32.h + + make distclean + + export CFLAGS="-O -g -isysroot $SDK -mmacosx-version-min=10.4 -arch x86_64 -arch ppc64" + ./configure --prefix=$DEPS_PREFIX --disable-dependency-tracking + + cp include/curl/curlbuild.h include/curl/curlbuild64.h + cp include/curl/curlbuild.h $DEPS_PREFIX/include/curl/curlbuild64.h + + make distclean + + export CFLAGS="-O -g -isysroot $SDK -mmacosx-version-min=10.4 $ARCH_FLAGS" ./configure --prefix=$DEPS_PREFIX --disable-dependency-tracking - make CFLAGS="-O -g -isysroot /Developer/SDKs/MacOSX10.4u.sdk -arch i386 -arch ppc" \ - LDFLAGS="-arch i386 -arch ppc" + + cat > include/curl/curlbuild.h <<EOF +#ifdef __LP64__ +#include "curlbuild64.h" +#else +#include "curlbuild32.h" +#endif +EOF + + make CFLAGS="-O -g -isysroot $SDK $ARCH_FLAGS" \ + LDFLAGS="$ARCH_FLAGS" make install else ./configure --prefix=$DEPS_PREFIX diff --git a/Tools/wx/packaging/build-mac-installer.py b/Tools/wx/packaging/build-mac-installer.py index d0ef945..8231049 100644 --- a/Tools/wx/packaging/build-mac-installer.py +++ b/Tools/wx/packaging/build-mac-installer.py @@ -70,7 +70,7 @@ if sys.platform.startswith("darwin"): wx_root = "/usr/local/lib/wxPython-unicode-%s" % wx.__version__ sp_root = "%s/lib/python%s/site-packages" % (wx_root, py_version) sitepackages = "%s/wx-%s-mac-unicode/wx" % (sp_root, wx_version[:3]) -prefix = wxroot + "/lib" +prefix = wx_root + "/lib" def mac_update_dependencies(dylib, prefix): """ @@ -131,7 +131,7 @@ try: shutil.copy(afile, wxroot) if sys.platform.startswith("darwin"): - dylib_path = os.path.join(wxpythonroot, "libwxwebkit.dylib") + dylib_path = os.path.join(wxroot, "libwxwebkit.dylib") os.system("install_name_tool -id %s %s" % (os.path.join(prefix, "libwxwebkit.dylib"), dylib_path)) mac_update_dependencies(dylib_path, prefix) mac_update_dependencies(os.path.join(wxpythonroot, "_webview.so"), prefix) @@ -140,7 +140,7 @@ try: if not os.path.exists(demodir): os.makedirs(demodir) - shutil.copy(os.path.join(wxwk_root, "WebKit", "wx", "bindings", "python", "samples", "simple.py"), demodir) + shutil.copy(os.path.join(wxwk_root, "Source", "WebKit", "wx", "bindings", "python", "samples", "simple.py"), demodir) if os.path.exists(pkgname + ".pkg"): shutil.rmtree(pkgname + ".pkg") @@ -152,7 +152,6 @@ try: '--domain system', '--root-volume-only', '--root ' + installroot, - '--resources %s/mac/resources' % script_dir, '--verbose' ] diff --git a/Tools/wx/packaging/build-win-installer.py b/Tools/wx/packaging/build-win-installer.py index ffbdd19..553d1b3 100644 --- a/Tools/wx/packaging/build-win-installer.py +++ b/Tools/wx/packaging/build-win-installer.py @@ -31,6 +31,8 @@ import datetime import glob from subprocess import * +import wx + script_dir = os.path.abspath(os.path.dirname(__file__)) sys.path.append(os.path.abspath(os.path.join(script_dir, "..", "build"))) @@ -85,7 +87,13 @@ CopyMode: alwaysoverwrite; Source: *.py; DestDir: "{app}" installerTemplate = open("wxWebKitInstaller.iss.in", "r").read() + wx_version = '%d.%d' % (wx.MAJOR_VERSION, wx.MINOR_VERSION) + if wx.MINOR_VERSION % 2 == 1: + wx_version += ".%d" % wx.RELEASE_VERSION + installerTemplate = installerTemplate.replace("msw-unicode", "msw") + installerTemplate = installerTemplate.replace("<<VERSION>>", date) + installerTemplate = installerTemplate.replace("<<WXVERSION>>", wx_version) installerTemplate = installerTemplate.replace("<<ROOTDIR>>", wxwebkit_dir ) installerTemplate = installerTemplate.replace("<<PYTHONVER>>", sys.version[0:3] ) installerTemplate = installerTemplate.replace("<<FILES>>", fileList ) diff --git a/Tools/wx/packaging/wxWebKitInstaller.iss.in b/Tools/wx/packaging/wxWebKitInstaller.iss.in index ebc89d4..2312474 100644 --- a/Tools/wx/packaging/wxWebKitInstaller.iss.in +++ b/Tools/wx/packaging/wxWebKitInstaller.iss.in @@ -17,7 +17,7 @@ UninstallFilesDir={app}\Uninstall Compression=bzip/9 SourceDir=<<ROOTDIR>> OutputDir=win-installer -OutputBaseFilename=wxWebKit-wx2.8-Py<<PYTHONVER>>-<<VERSION>> +OutputBaseFilename=wxWebKit-wx<<WXVERSION>>-Py<<PYTHONVER>>-<<VERSION>> DisableStartupPrompt=yes AllowNoIcons=yes DisableProgramGroupPage=yes @@ -57,7 +57,7 @@ begin PythonDir := 'C:\Put a directory on PYTHONPATH here\'; end; end; - InstallDir := PythonDir + '\Lib\site-packages\wx-2.8-msw-unicode\wx\'; + InstallDir := PythonDir + '\Lib\site-packages\wx-<<WXVERSION>>-msw-unicode\wx\'; Result := True; end; |