diff options
Diffstat (limited to 'WebKitTools')
107 files changed, 4076 insertions, 440 deletions
diff --git a/WebKitTools/BuildSlaveSupport/build.webkit.org-config/config.json b/WebKitTools/BuildSlaveSupport/build.webkit.org-config/config.json index 71c20f0..f39e10c 100644 --- a/WebKitTools/BuildSlaveSupport/build.webkit.org-config/config.json +++ b/WebKitTools/BuildSlaveSupport/build.webkit.org-config/config.json @@ -91,7 +91,7 @@ { "name": "Windows Release (Build)", "type": "Build", "builddir": "win-release", "platform": "win", "configuration": "release", "architectures": ["i386"], - "triggers": ["win-release-tests"], + "triggers": ["win-release-tests", "win-release-tests-wk2"], "slavenames": ["apple-windows-2", "test-slave"] }, { @@ -102,7 +102,7 @@ { "name": "Windows Debug (Build)", "type": "Build", "builddir": "win-debug", "platform": "win", "configuration": "debug", "architectures": ["i386"], - "triggers": ["win-debug-tests", "win-debug-tests-wk2"], + "triggers": ["win-debug-tests"], "slavenames": ["apple-windows-1", "test-slave"] }, { @@ -240,8 +240,8 @@ { "type": "Triggerable", "name": "win-debug-tests", "builderNames": ["Windows Debug (Tests)"] }, - { "type": "Triggerable", "name": "win-debug-tests-wk2", - "builderNames": ["Windows Debug (WebKit2 Tests)"] + { "type": "Triggerable", "name": "win-release-tests-wk2", + "builderNames": ["Windows Release (WebKit2 Tests)"] } ] } diff --git a/WebKitTools/BuildSlaveSupport/build.webkit.org-config/master.cfg b/WebKitTools/BuildSlaveSupport/build.webkit.org-config/master.cfg index 5c44525..97641bf 100644 --- a/WebKitTools/BuildSlaveSupport/build.webkit.org-config/master.cfg +++ b/WebKitTools/BuildSlaveSupport/build.webkit.org-config/master.cfg @@ -305,6 +305,51 @@ class RunGtkAPITests(shell.Test): return [self.name] +class RunQtAPITests(shell.Test): + name = "API tests" + description = ["API tests running"] + descriptionDone = ["API tests"] + command = ["python", "./WebKitTools/Scripts/run-qtwebkit-tests", + "--output-file=qt-unit-tests.html", "--do-not-open-results", + WithProperties("WebKitBuild/%(configuration_pretty)s/WebKit/qt/tests/")] + + def start(self): + self.setProperty("configuration_pretty", self.getProperty("configuration").title()) + return shell.Test.start(self) + + def commandComplete(self, cmd): + shell.Test.commandComplete(self, cmd) + + logText = cmd.logs['stdio'].getText() + foundItems = re.findall("TOTALS: (?P<passed>\d+) passed, (?P<failed>\d+) failed, (?P<skipped>\d+) skipped", logText) + + self.incorrectTests = 0 + self.statusLine = [] + + if foundItems: + self.incorrectTests = int(foundItems[0][1]) + if self.incorrectTests > 0: + self.statusLine = [ + "%s passed, %s failed, %s skipped" % (foundItems[0][0], foundItems[0][1], foundItems[0][2]) + ] + + def evaluateCommand(self, cmd): + if self.incorrectTests: + return WARNINGS + + if cmd.rc != 0: + return FAILURE + + return SUCCESS + + def getText(self, cmd, results): + return self.getText2(cmd, results) + + def getText2(self, cmd, results): + if results != SUCCESS and self.incorrectTests: + return self.statusLine + + return [self.name] class RunWebKitLeakTests(RunWebKitTests): def start(self): @@ -421,6 +466,8 @@ class BuildAndTestFactory(Factory): self.addStep(ExtractTestResults) if platform == "gtk": self.addStep(RunGtkAPITests) + if platform == "qt": + self.addStep(RunQtAPITests) class BuildAndTestLeaksFactory(BuildAndTestFactory): TestClass = RunWebKitLeakTests diff --git a/WebKitTools/ChangeLog b/WebKitTools/ChangeLog index 1c7d1bf..a5e6893 100644 --- a/WebKitTools/ChangeLog +++ b/WebKitTools/ChangeLog @@ -1,3 +1,1241 @@ +2010-11-05 Adam Roben <aroben@apple.com> + + Make webkitpy.common.system.executive_unittest pass when running under + Win32 Python + + Fixes <http://webkit.org/b/49033>. + + Reviewed by Dave Levin and Eric Seidel. + + * Scripts/webkitpy/common/system/executive.py: + (Executive._run_command_with_teed_output): Pass the arguments through + encode_argument_if_needed rather than using Cygwin-specific code here. + (Executive.run_and_throw_if_fail): Use child_process_encoding to decode + the output. + (Executive.run_command): Use encode_argument_if_needed to encode the + arguments and child_process_encoding to decode the output. + (Executive._child_process_encoding): Returns the encoding that should be + used when communicating with child processes. On Windows we use mbcs, + which maps to the current code page. On all other platforms we use + UTF-8. + (Executive._should_encode_child_process_arguments): Returns True if + arguments to child processes need to be encoded. This is currently + only needed on Cygwin and Win32 Python 2.x. + (Executive._encode_argument_if_needed): Encode the argument using + child_process_encoding if we need to encode arguments to child + processes on this platform. + + * Scripts/webkitpy/common/system/executive_unittest.py: + (never_ending_command): Added. Returns arguments to run a command that + will not quit until we kill it. On Windows we use wmic, on other + platforms we use yes. + (ExecutiveTest.test_run_command_with_unicode): Changed to expect the + mbcs encoding to be used and for output from the child processes to + have been roundtripped through encode/decode on Win32 Python. When + UTF-8 is the encoding the roundtripping is undetectable, but with mbcs + it's possible that some characters will not be able to be converted + and will be replaced by question marks; the round-tripping allows us + to expect this result. + + (ExecutiveTest.test_kill_process): + (ExecutiveTest.test_kill_all): + Use never_ending_command instead of invoking "yes" directly. Expect an + exit code of 1 when using Win32 Python, as that's what seems to happen. + +2010-11-08 Adam Roben <aroben@apple.com> + + Roll out r71532 + + It broke the build for Cygwin 1.7 installs. Cygwin 1.7's default + .bashrc unsets %TEMP%, which broke copy-tools.cmd. + + * Scripts/webkitdirs.pm: + +2010-11-08 Tony Chang <tony@chromium.org> + + Reviewed by Adam Barth. + + run platform/chromium/plugins/nested-plugin-objects.html on all platforms + https://bugs.webkit.org/show_bug.cgi?id=49094 + + This tests that objects created by plugins are proplery cleaned up. + + * DumpRenderTree/TestNetscapePlugIn/PluginObject.cpp: + (testPassTestObject): + (pluginInvoke): + * DumpRenderTree/TestNetscapePlugIn/TestObject.cpp: + (testAllocate): + (testDeallocate): + (testGetProperty): + (testConstruct): + +2010-11-08 Adam Roben <aroben@apple.com> + + Mark Windows builds triggered from Perl as being non-interactive + + This affects whether some of our scripts will show alerts vs. printing + to the build log. + + Fixes <http://webkit.org/b/49181> Windows build fail mysteriously when + .vsprops files are updated + + Reviewed by Steve Falkenburg. + + * Scripts/webkitdirs.pm: + (buildVisualStudioProject): Set WEBKIT_NONINTERACTIVE_BUILD to 1. + +2010-11-08 Gabor Rapcsanyi <rgabor@inf.u-szeged.hu> + + Reviewed by Ojan Vafai. + + Make http locking default in NRWT. + https://bugs.webkit.org/show_bug.cgi?id=48053 + + * Scripts/webkitpy/layout_tests/layout_package/dump_render_tree_thread.py: + * Scripts/webkitpy/layout_tests/run_webkit_tests.py: + +2010-11-08 Gabor Rapcsanyi <rgabor@inf.u-szeged.hu> + + Reviewed by Csaba Osztrogonác. + + [NRWT] If the http lock fails we shouldn't do any locking + https://bugs.webkit.org/show_bug.cgi?id=49164 + + If something goes wrong with the locking, the test should keep going. + + * Scripts/webkitpy/layout_tests/port/http_lock.py: + +2010-11-08 Adam Roben <aroben@apple.com> + + Switch back to using kCGImageAlphaPremultipliedFirst when generating + pixel dumps on Windows + + I changed this behavior in r71418 thinking that it was required for + getting plugins to show up in pixel dumps. But it doesn't seem to be + necessary, and was making it impossible to compare new Windows pixel + dumps with existing Windows or Mac pixel dumps (because ImageDiff won't + compare an image with alpha to an image without alpha). + + Fixes <http://webkit.org/b/49172> REGRESION (r71418): Can't compare + new Windows pixel results to existing Windows or Mac results + + Reviewed by Antti Koivisto. + + * DumpRenderTree/win/PixelDumpSupportWin.cpp: + (createBitmapContextFromWebView): Replaced kCGImageAlphaNoneSkipFirst + with kCGImageAlphaPremultipliedFirst. + +2010-11-08 Csaba Osztrogonac <ossy@webkit.org> + + Unreviewed, rolling out r71466. + http://trac.webkit.org/changeset/71466 + https://bugs.webkit.org/show_bug.cgi?id=48865 + + It broke layout tests on GTK bots. + + * DumpRenderTree/gtk/DumpRenderTree.cpp: + (createWebView): + +2010-11-08 Gabor Rapcsanyi <rgabor@inf.u-szeged.hu> + + Reviewed by Csaba Osztrogonác. + + Enable running of Qt API tests on BuildBot + https://bugs.webkit.org/show_bug.cgi?id=49004 + + * BuildSlaveSupport/build.webkit.org-config/master.cfg: + +2010-11-08 Eric Seidel <eric@webkit.org> + + Reviewed by Adam Barth. + + Add clean-review-queue command to remove closed bugs from the webkit.org/pending-review + https://bugs.webkit.org/show_bug.cgi?id=49160 + + Bugzilla doesn't automatically remove r? when a bug gets closed. + This script takes care of that for webkit.org. + + * Scripts/webkitpy/common/net/bugzilla.py: + * Scripts/webkitpy/tool/commands/upload.py: + +2010-11-07 Fumitoshi Ukai <ukai@chromium.org> + + Unreviewed, rolling out r71474. + http://trac.webkit.org/changeset/71474 + https://bugs.webkit.org/show_bug.cgi?id=48280 + + breaks chromium webkit tests + https://bugs.webkit.org/show_bug.cgi?id=49151 + + * Scripts/webkitpy/layout_tests/port/base.py: + * Scripts/webkitpy/layout_tests/port/base_unittest.py: + * Scripts/webkitpy/layout_tests/port/config.py: + * Scripts/webkitpy/layout_tests/port/config_unittest.py: + * Scripts/webkitpy/layout_tests/port/google_chrome_unittest.py: + * Scripts/webkitpy/layout_tests/port/webkit.py: + * Scripts/webkitpy/layout_tests/run_webkit_tests_unittest.py: + * Scripts/webkitpy/tool/mocktool.py: + +2010-11-07 Fumitoshi Ukai <ukai@chromium.org> + + Unreviewed, rolling out r71475. + http://trac.webkit.org/changeset/71475 + + breaks chromium webkit tests + https://bugs.webkit.org/show_bug.cgi?id=49151 + + * Scripts/webkitpy/common/newstringio.py: Removed. + * Scripts/webkitpy/common/newstringio_unittest.py: Removed. + * Scripts/webkitpy/common/system/executive_mock.py: Removed. + * Scripts/webkitpy/common/system/filesystem_mock.py: Removed. + * Scripts/webkitpy/layout_tests/port/config_mock.py: Removed. + +2010-11-06 Dirk Pranke <dpranke@chromium.org> + + Unreviewed, build fix. + + Add files inexplicably not committed in r71474 as part of the + fix for bug 48280. + + * Scripts/webkitpy/common/newstringio.py: Added. + * Scripts/webkitpy/common/newstringio_unittest.py: Added. + * Scripts/webkitpy/common/system/executive_mock.py: Added. + * Scripts/webkitpy/common/system/filesystem_mock.py: Added. + * Scripts/webkitpy/layout_tests/port/config_mock.py: Added. + +2010-11-06 Dirk Pranke <dpranke@chromium.org> + + Reviewed by Eric Siedel. + + new-run-webkit-tests: update port/base and port/webkit to use the + new FileSystem and Config abstractions, pulling more logic out of + the base Port classes into separate, mockable objects. + + Also create a MockFileSystem object, a MockConfig object, move + MockExecutive into common/system to be next to executive, and + update the config object to use a FileSystem. + + https://bugs.webkit.org/show_bug.cgi?id=48280 + + * Scripts/webkitpy/common/newstringio.py: Added. + * Scripts/webkitpy/common/newstringio_unittest.py: Added. + * Scripts/webkitpy/common/system/executive_mock.py: Added. + * Scripts/webkitpy/common/system/filesystem_mock.py: Added. + * Scripts/webkitpy/layout_tests/port/base.py: + * Scripts/webkitpy/layout_tests/port/base_unittest.py: + * Scripts/webkitpy/layout_tests/port/config.py: + * Scripts/webkitpy/layout_tests/port/config_mock.py: + * Scripts/webkitpy/layout_tests/port/config_unittest.py: + * Scripts/webkitpy/layout_tests/port/google_chrome_unittest.py: + * Scripts/webkitpy/layout_tests/port/webkit.py: + * Scripts/webkitpy/layout_tests/run_webkit_tests_unittest.py: + * Scripts/webkitpy/tool/mocktool.py: + +2010-11-06 Dirk Pranke <dpranke@chromium.org> + + Unreviewed, build breakage. + + Apparently I uploaded the wrong version of the file to fix 49122 + and neither Eric or I noticed - it was missing a dirname() call. + Fixing ... + + https://bugs.webkit.org/show_bug.cgi?id=49122 + + * Scripts/webkitpy/common/checkout/scm.py: + +2010-11-06 Dirk Pranke <dpranke@chromium.org> + + Reviewed by Eric Seidel. + + webkitpy/tool/* unittests change cwd and don't clean up properly + + https://bugs.webkit.org/show_bug.cgi?id=49122 + + * Scripts/webkitpy/common/checkout/scm.py: + +2010-11-05 Chris Marrin <cmarrin@apple.com> + + Reviewed by Simon Fraser. + + suspendAnimations/resumeAnimations not present in WebKit2 + https://bugs.webkit.org/show_bug.cgi?id=49109 + + * WebKitTestRunner/InjectedBundle/Bindings/LayoutTestController.idl: + * WebKitTestRunner/InjectedBundle/LayoutTestController.cpp: + (WTR::LayoutTestController::suspendAnimations): + (WTR::LayoutTestController::resumeAnimations): + * WebKitTestRunner/InjectedBundle/LayoutTestController.h: + +2010-11-05 Tony Chang <tony@chromium.org> + + Reviewed by David Levin. + + cleanup style in TestNetscapePlugIn/PluginObject.cpp + https://bugs.webkit.org/show_bug.cgi?id=49044 + + * DumpRenderTree/TestNetscapePlugIn/PluginObject.cpp: + (getPluginClass): + (pluginGetProperty): + (pluginSetProperty): + (variantToIdentifier): + (testCallback): + (getURL): + (getURLNotify): + (testInvokeDefault): + (testGetProperty): + (testDocumentOpen): + (testWindowOpen): + (pluginInvoke): + (handleCallback): + (notifyStream): + * DumpRenderTree/TestNetscapePlugIn/PluginObject.h: + +2010-11-05 Eric Seidel <eric@webkit.org> + + Reviewed by David Levin. + + Add QueueStatusServer/__init__.py so others can run the QueueStatusServer tests + https://bugs.webkit.org/show_bug.cgi?id=49032 + + I wrote this file as part of bug 47847, but I forgot to commit it. + No one else noticed it missing because test-webkitpy knows how + to recover in the case where it can't import QueueStatusServer + (which generally occurs due to not having installed the AppEngine SDK). + + * QueueStatusServer/__init__.py: Added. + * QueueStatusServer/model/workitems_unittest.py: + - Remove a test which fails. This was probably landed (by me) + from my other machine, which since this __init__.py was missing + I never noticed the failure and landed this invalid test. + Sadly we can't really test remove_work_item as it depends + on .key() working. .key() will throw unless the object + has already been saved it seems. + This may be a mis-design in our remove_work_item implementation, + but for now, just removing the test. + +2010-11-04 Adam Roben <aroben@apple.com> + + Teach check-webkit-style about TestNetscapePlugIn + + Fixes <http://webkit.org/b/49030> check-webkit-style is ignorant of + TestNetscapePlugIn's coding conventions + + Reviewed by John Sullivan. + + * Scripts/webkitpy/style/checker.py: Lump TestNetscapePlugIn in with + WebKitAPITest and TestWebKitAPI in having different include order and + naming conventions than WebCore. Added some comments about why the + exceptions exist. + +2010-11-04 Adam Roben <aroben@apple.com> + + Add a test that shows that windowed plugins are able to paint + + Somehow we never had a test for this before. + + Fixes <http://webkit.org/b/49029> Should add a test that shows + windowed plugins can paint + + Reviewed by Jon Honeycutt. + + * DumpRenderTree/TestNetscapePlugIn/Tests/win/DrawsGradient.cpp: Added. + (DrawsGradient::DrawsGradient): + (DrawsGradient::wndProc): We handle the WM_PAINT and WM_PRINTCLIENT messages. + + (DrawsGradient::onPaint): + (DrawsGradient::onPrintClient): + These both just call through to paint. + + (DrawsGradient::paint): Fills our client area with some gradients. + + * DumpRenderTree/TestNetscapePlugIn/win/TestNetscapePlugin.vcproj: Link + against Msimg32.lib for ::GradientFill and added DrawsGradient. + + * DumpRenderTree/win/PixelDumpSupportWin.cpp: + (createBitmapContextFromWebView): Use WM_PRINT instead of + WM_PRINTCLIENT so that ::DefWindowProc will send + WM_PRINT/WM_PRINTCLIENT messages to the WebView's child windows. + Replaced kCGImageAlphaPremultipledFirst with kCGImageAlphaNoneSkipFirst + because GDI doesn't support alpha and kCGImageBitmapOrder32Little with + kCGImageBitmapOrder32Host because, who knows, maybe someday Windows + will run on a big-endian platform. + +2010-11-04 Adam Roben <aroben@apple.com> + + Extract much of NPNInvalidateRectInvalidatesWindow's code into a + WindowedPluginTest base class + + The base class takes care of subclassing the plugin's window so that a + custom WNDPROC is called. This will make it easier to write tests that + need to handle window messages. + + Fixes <http://webkit.org/b/49028> It's hard to write a PluginTest with + a custom WNDPROC + + Reviewed by Jon Honeycutt. + + * DumpRenderTree/TestNetscapePlugIn/Tests/win/NPNInvalidateRectInvalidatesWindow.cpp: + (NPNInvalidateRectInvalidatesWindow::NPNInvalidateRectInvalidatesWindow): + (NPNInvalidateRectInvalidatesWindow::NPP_SetWindow): + (NPNInvalidateRectInvalidatesWindow::wndProc): + (NPNInvalidateRectInvalidatesWindow::testInvalidateRect): + Moved code from here to WindowedPluginTest. Changed to use window() + instead of m_window. + + * DumpRenderTree/TestNetscapePlugIn/win/TestNetscapePlugin.vcproj: + Added WindowedPluginTest and added TestNetscapePlugIn/win to the + include path. Also reordered the include path to make a little more + sense and simplified the entry that added TestNetscapePlugIn itself to + the include path. + + * DumpRenderTree/TestNetscapePlugIn/win/WindowedPluginTest.cpp: Added. + (WindowedPluginTest::WindowedPluginTest): + (WindowedPluginTest::NPP_SetWindow): + (WindowedPluginTest::staticWndProc): + * DumpRenderTree/TestNetscapePlugIn/win/WindowedPluginTest.h: Added. + (WindowedPluginTest::window): + Code came from NPNInvalidateRectInvalidatesWindow. + +2010-11-04 Adam Roben <aroben@apple.com> + + Add a plugin test to show that windowed plugins are clipped correctly + + Fixes <http://webkit.org/b/49024> <rdar://problem/8487847> Windowed + plugins aren't clipped in WebKit2 on Windows + + Reviewed by Jon Honeycutt. + + * DumpRenderTree/TestNetscapePlugIn/Tests/win/WindowRegionIsSetToClipRect.cpp: Added. + (WindowRegionIsSetToClipRect::WindowRegionIsSetToClipRect): Initialize members. + (WindowRegionIsSetToClipRect::NPP_SetWindow): Check that our window + region matches the clip rect we know we should have based on + window-region-is-set-to-clip-rect.html, and check that our window class + doesn't have the CS_PARENTDC style. + + * DumpRenderTree/TestNetscapePlugIn/win/TestNetscapePlugin.vcproj: + Added WindowRegionIsSetToClipRect. + +2010-11-05 Alejandro G. Castro <alex@igalia.com> + + Reviewed by Martin Robinson. + + [GTK] Avoid font hinting in the DRT + https://bugs.webkit.org/show_bug.cgi?id=48548 + + Change the settings to avoid font hinting, it was causing + different results depending on the distribution. + + * DumpRenderTree/gtk/DumpRenderTree.cpp: + (initializeGtkFontSettings): + * DumpRenderTree/gtk/fonts/fonts.conf: + +2010-11-05 Eric Seidel <eric@webkit.org> + + Reviewed by Adam Barth. + + build-webkit spams system.log by repeatedly checking for PBXProductDirectory in com.apple.Xcode + https://bugs.webkit.org/show_bug.cgi?id=49051 + + This is a speculative fix. The unit tests cover these methods, however + I don't know if this will fully stop the system.log spam. + + * Scripts/webkitpy/layout_tests/port/base.py: + * Scripts/webkitpy/layout_tests/port/webkit.py: + +2010-11-05 Eric Seidel <eric@webkit.org> + + Reviewed by Adam Barth. + + Add basic support for showing bot id on /queue-status/ pages + https://bugs.webkit.org/show_bug.cgi?id=49037 + + This support is really simple. Eventually we'll want to + show the bot id in the lock table too, but we don't have + that information stored in the server yet. + + * QueueStatusServer/handlers/queuestatus.py: + * QueueStatusServer/handlers/queuestatus_unittest.py: Added. + * QueueStatusServer/templates/includes/singlequeuestatus.html: + +2010-11-04 Dirk Pranke <dpranke@chromium.org> + + Reviewed by Adam Barth. + + Create a filesystem wrapper that we can use to enforce + particular conventions and use for mocking and dependency + injection down the line. + + https://bugs.webkit.org/show_bug.cgi?id=48144 + + * Scripts/webkitpy/common/system/filesystem.py: Added. + * Scripts/webkitpy/common/system/filesystem_unittest.py: Added. + +2010-11-04 Mihai Parparita <mihaip@chromium.org> + + Reviewed by Tony Chang. + + run_webkit_tests_unittest fails under Python 2.5 + https://bugs.webkit.org/show_bug.cgi?id=49043 + + Switch from itertools.chain.from_iterable (which was added in 2.6) + to using itertools.chain directly. + + * Scripts/webkitpy/layout_tests/run_webkit_tests_unittest.py: + +2010-11-04 Mihai Parparita <mihaip@chromium.org> + + Unreviewed fix to webkit-patch rebaseline-server so that it runs under + Python 2.5 (it needs an import to use the with statement). + + * Scripts/webkitpy/tool/commands/rebaselineserver.py: + +2010-11-04 Dirk Pranke <dpranke@chromium.org> + + Reviewed by Adam Barth. + + new-run-webkit-tests: split out webkit-specific configuration stuff into a new module + + The current NRWT code has webkit-specific configuration code (like + _script_path, default configuration, etc.) mixed in with + layout-test-specific stuff in port/base. The configuration code + should be split out into a separate module for easier mocking, + testing, and isolation. + + https://bugs.webkit.org/show_bug.cgi?id=48264 + + * Scripts/webkitpy/layout_tests/port/config.py: Added. + * Scripts/webkitpy/layout_tests/port/config_unittest.py: Added. + +2010-11-04 Mihai Parparita <mihaip@chromium.org> + + Reviewed by Tony Chang. + + Rebaseline server: initial framework + https://bugs.webkit.org/show_bug.cgi?id=48892 + + Adds the basic framework for the rebaseline server (details at + http://webkit.org/b/47761). Includes the rebaseline-server webkit-patch + command, which starts an HTTP server that can serve static files or + invoke handler methods on a class. + + * Scripts/webkitpy/tool/commands/__init__.py: + * Scripts/webkitpy/tool/commands/data/rebaselineserver/index.html: Added. + * Scripts/webkitpy/tool/commands/data/rebaselineserver/main.css: Added. + * Scripts/webkitpy/tool/commands/data/rebaselineserver/main.js: Added. + * Scripts/webkitpy/tool/commands/rebaselineserver.py: Added. + +2010-11-04 Dirk Pranke <dpranke@chromium.org> + + Reviewed by James Robinson. + + new-run-webkit-tests wasn't using DRT by default for + --platform chromium-gpu + + The default value was set to False instead of None, which meant + that the platform specific logic wasn't firing to change the + value to True (b/c we were afraid we'd be overriding the user + preference). + + https://bugs.webkit.org/show_bug.cgi?id=49038 + + * Scripts/webkitpy/layout_tests/run_webkit_tests.py: + +2010-11-04 Tony Chang <tony@chromium.org> + + Reviewed by Adam Barth. + + make platform/chromium/plugins/multiple-plugins.html pass on all platforms + https://bugs.webkit.org/show_bug.cgi?id=49026 + + Have the testObject.bar property return the string "bar". This lets + us run and pass platform/chromium/plugins/multiple-plugins.html on all + platforms. + + * DumpRenderTree/TestNetscapePlugIn/TestObject.cpp: + (testGetProperty): + +2010-11-04 Mihai Parparita <mihaip@chromium.org> + + Reviewed by Tony Chang. + + NRWT doesn't have good test coverage for --run-chunk, --batch-size, --run-part, etc. + https://bugs.webkit.org/show_bug.cgi?id=48878 + + Add get_tests_run so that it's easy to see which tests get run (and with + what batching) for a given flag combination. Flesh out the various + test cases that have FIXMEs. + + Also fixes an off-by-one error (batch sizes were one larger than + expected) and makes --run-part also have wraparound behavior, like + --run-chunk. + + * Scripts/webkitpy/layout_tests/layout_package/dump_render_tree_thread.py: + * Scripts/webkitpy/layout_tests/run_webkit_tests.py: + * Scripts/webkitpy/layout_tests/run_webkit_tests_unittest.py: + +2010-11-04 Erik Arvidsson <arv@chromium.org> + + Reviewed by Dimitri Glazkov. + + Support box-sizing without the vendor prefix + https://bugs.webkit.org/show_bug.cgi?id=36713 + + Based on patch by Peter Beverloo <peter@lvp-media.com> + + * iExploder/htdocs/cssproperties.in: Change -webkit-box-sizing to box-sizing. + +2010-11-04 Csaba Osztrogonác <ossy@webkit.org> + + Unreviewed rollout r71340, because it broke Chromium Windows bot. + + * Scripts/webkitpy/layout_tests/layout_package/dump_render_tree_thread.py: + * Scripts/webkitpy/layout_tests/run_webkit_tests.py: + +2010-11-04 Gabor Rapcsanyi <rgabor@inf.u-szeged.hu> + + Reviewed by Ojan Vafai. + + Make http locking default in NRWT. + https://bugs.webkit.org/show_bug.cgi?id=48053 + + * Scripts/webkitpy/layout_tests/layout_package/dump_render_tree_thread.py: + * Scripts/webkitpy/layout_tests/run_webkit_tests.py: + +2010-11-04 Gabor Rapcsanyi <rgabor@inf.u-szeged.hu> + + Reviewed by Eric Seidel. + + [NRWT] Clear invalid http locks on Windows platform as well + https://bugs.webkit.org/show_bug.cgi?id=48515 + + * Scripts/webkitpy/common/system/executive.py: + * Scripts/webkitpy/common/system/executive_unittest.py: + * Scripts/webkitpy/layout_tests/port/http_lock.py: + +2010-11-02 Adam Roben <aroben@apple.com> + + Reduce our dependence on coreutils when running Python tests + + This patch introduces versions of the standard echo and cat utilities + implemented in Python. They are probably missing features of their + coreutils equivalents, but they can do what's necessary for our Python + tests. This is useful on Windows, where these utilities typically + aren't available. + + Fixes <http://webkit.org/b/48883> executive_unittest relies on echo + and cat utilities from coreutils, which are not present on Windows + + Reviewed by Eric Seidel. + + * Scripts/webkitpy/common/system/executive_unittest.py: Changed to use + our Python-based echo and cat. + + * Scripts/webkitpy/common/system/fileutils.py: Added. + (make_stdout_binary): On Windows, puts sys.stdout into binary mode so + that \n won't be translated into \r\n. I couldn't think of a good way + to test this directly without touching the filesystem, but it is tested + indirectly by echo_unittest. + + * Scripts/webkitpy/test/cat.py: Added. + (command_arguments): Returns a list for invoking cat with the given arguments. + (main): Acts like a simplified version of the coreutils cat utility. + + * Scripts/webkitpy/test/cat_unittest.py: Added. + (CatTest.assert_cat): Runs cat with the given input and ensures the + output matches the input. + (CatTest.test_basic): Performs a simple test of cat. + (CatTest.test_no_newline): Tests what happens when the input string + doesn't have a trailing newline. + (CatTest.test_unicode): Tests passing a unicode string to cat. + (CatTest.test_as_command): Tests running cat as a separate command. + + * Scripts/webkitpy/test/echo.py: Added. + (command_arguments): Returns a list for invoking echo with the given arguments. + (main): Acts like a simplified version of the coreutils echo utility. + + * Scripts/webkitpy/test/echo_unittest.py: Added. + (EchoTest.test_basic): Performs a simple test of echo. + (EchoTest.test_no_newline): Tests passing -n to echo to suppress the + trailing newline. + (EchoTest.test_unicode): Tests passing unicode and non-unicode strings + to echo. + (EchoTest.test_argument_order): Tests what happens when -n is not the + first argument. + (EchoTest.test_empty_arguments): Tests what happens when you pass [] to + echo.main. + (EchoTest.test_no_arguments): Tests what happens when you call + echo.main with no arguments. + (EchoTest.test_as_command): Tests running echo as a separate command. + +2010-11-04 Renata Hodovan <reni@inf.u-szeged.hu> + + Unreviewed: Add myself to the list of Committers. + + * Scripts/webkitpy/common/config/committers.py: + +2010-11-04 Andreas Kling <kling@webkit.org> + + Reviewed by Kenneth Rohde Christiansen. + + [Qt] Hook into QWebPage::scrollRequested for resizes-to-contents mode + + In RTC mode the QGraphicsWebView item is the size of the contents, + scrolling works a bit differently (we need to react to scrollRequested.) + + Normally QGraphicsView will replay the last mouse event when scrolling, + so to prevent WebKit from getting confused by this we temporarily make + the QGraphicsView non-interactive. + + * QtTestBrowser/webview.cpp: + (WebViewGraphicsBased::setPage): + (WebViewGraphicsBased::scrollRequested): + * QtTestBrowser/webview.h: + +2010-11-04 Tor Arne Vestbø <tor.arne.vestbo@nokia.com> + + Reviewed by Andreas Kling. + + Use OS(MAC_OS_X) rather than PLATFORM(MAC) in TestControllerQt + + PLATFORM(MAC) is not defined for the Qt port, as it refers to + the Mac-port, not the Mac OS X operating system. + + * WebKitTestRunner/qt/TestControllerQt.cpp: + (WTR::isExistingLibrary): + +2010-11-04 Leonid Ebril <leonid.ebril@nokia.com> + + Reviewed by Andreas Kling. + + [Qt] Adding iphone user agent string the user agent list for QtTestBrowser + https://bugs.webkit.org/show_bug.cgi?id=48869 + + * QtTestBrowser/useragentlist.txt: + +2010-11-03 Adam Roben <aroben@apple.com> + + Always use uppercase drive names in strings returned by abspath_to_uri + + Some versions of cygpath use lowercase drive letters while others use + uppercase, which makes it hard to test the output of code that uses + cygpath. + + Fixes <http://webkit.org/b/48914> webkitpy.common.system.path_unittest + fails with Cygwin 1.5 + + Reviewed by Eric Seidel. + + * Scripts/webkitpy/common/system/path.py: + (cygpath): Updated the docstring to indicate that only absolute paths + should be passed for now (though relative paths will work fine). + (_Cygpath.convert): Upper-case the first letter of the converted Windows path. + +2010-11-03 George Guo <George.Guo@Nokia.com> + + Reviewed by Andreas Kling. + + [Qt] QtTestBrowser : set mmp rule pageddata in Symbian + https://bugs.webkit.org/show_bug.cgi?id=48767 + + Paging is needd on Symbian devices to support benchmarks tests like + dromaeo.com and Celtic Kane that need a lot of memory to run + + * QtTestBrowser/QtTestBrowser.pro: + +2010-11-03 Jenn Braithwaite <jennb@chromium.org> + + Reviewed by Dmitry Titov. + + Chromium: Update resource tracking when moving a frame between documents + https://bugs.webkit.org/show_bug.cgi?id=48363 + + * DumpRenderTree/chromium/WebViewHost.cpp: + (WebViewHost::assignIdentifierToRequest): + Always put resource id in map so we can make assumptions about its + presence. + (WebViewHost::removeIdentifierForRequest): + Added. + (WebViewHost::didFinishResourceLoad): + (WebViewHost::didFailResourceLoad): + Check existence of resource id before removing from map. + * DumpRenderTree/chromium/WebViewHost.h: + +2010-11-03 Victor Wang <victorw@chromium.org> + + Reviewed by Adam Barth. + + [Chromium] update buildbot names in chromium rebaseline tool. + + https://bugs.webkit.org/show_bug.cgi?id=48881 + + * Scripts/webkitpy/layout_tests/rebaseline_chromium_webkit_tests.py: + +2010-11-03 Darin Adler <darin@apple.com> + + Updated Xcode projects by opening them with Xcode 3.2.4. + Updated svn:ignore for Xcode projects. + + * MiniBrowser/MiniBrowser.xcodeproj: Added property svn:ignore. + * TestWebKitAPI/TestWebKitAPI.xcodeproj: Added property svn:ignore. + * WebKitLauncher/WebKitLauncher.xcodeproj: Modified property svn:ignore. + * WebKitLauncher/WebKitLauncher.xcodeproj/project.pbxproj: Updated with Xcode 3.2.4. + +2010-11-03 Adam Roben <aroben@apple.com> + + Stop waiting for messages from the web process after a timeout elapses + + TestController::runUntil now takes a timeout parameter that specifies + how long to wait for the condition to become true. WebKitTestRunner + takes a --timeout flag that specifies how long the timeout should be. + run-webkit-tests passes this flag to WebKitTestRunner so its timeout + will be similar to run-webkit-tests. + + Fixes <http://webkit.org/b/43047> <rdar://problem/8365833> + WebKitTestRunner waits forever if the web process crashes + + Reviewed by Darin Adler and Anders Carlsson. + + * Scripts/old-run-webkit-tests: + (top level): Moved the GuardMalloc timeout adjustment here from + readFromDumpToolWithTimer. + (openDumpTool): Make WTR use a timeout similar to but slightly shorter + than the one that was specified on the command line. + + * WebKitTestRunner/TestController.cpp: + (WTR::TestController::TestController): Initialize our timeout values. + (WTR::TestController::initialize): Parse the --timeout flag and use it + to modify our timeout values. + (WTR::TestController::resetStateToConsistentValues): Changed to use a + short timeout while waiting for the web process to reset and to return + a boolean indicating whether we were able to reset the web process. + Uses a 5-second timeout while waiting for the process to be reset. + (WTR::TestController::runTest): Changed to return a boolean indicating + whether we were able to reset the web process (and thus run the test). + (WTR::TestController::runUntil): Call through to platformRunUntil. + + (WTR::TestController::runTestingServerLoop): + (WTR::TestController::run): + Changed to bail if any test can't be run. This will cause the process + to exit. (Unfortunately this will make run-webkit-tests think we + crashed; see <http://webkit.org/b/48943>.) + + * WebKitTestRunner/TestController.h: Added platformRunUntil, + m_longTimeout, and m_shortTimeout. + + * WebKitTestRunner/TestInvocation.cpp: + (WTR::TestInvocation::invoke): Use a short timeout when waiting for the + initial response and a long timeout when waiting for the test to + complete. Check whether runUntil timed out and print an error message + if so. + + * WebKitTestRunner/mac/TestControllerMac.mm: + (WTR::TestController::platformRunUntil): Renamed from runUntil. Pass + [NSDate distantPast] to -[NSRunLoop runMode:beforeDate:] so that we + won't block waiting for the run loop. Only loop until the timeout + elapses. + + * WebKitTestRunner/qt/TestControllerQt.cpp: + (WTR::TestController::platformRunUntil): Renamed from runUntil. Added a + FIXME about honoring the timeout. + + * WebKitTestRunner/win/TestControllerWin.cpp: + (WTR::TestController::platformRunUntil): Renamed from runUntil. Use + ::MsgWaitForMultipleObjectsEx to implement the timeout. Changed to use + ::PeekMessageW so that we don't block waiting for messages to become + available. + +2010-11-03 Adam Roben <aroben@apple.com> + + Add a plugin test that evaluates JS after removing the plugin element + from the document + + This test replaces platform/win/plugins/plugin-delayed-destroy.html. + That test was made to prevent a crash very similar to this one, but + unfortunately tested only the mechanism that prevented the crash and + not whether the crash itself was prevented. Since WebKit2 uses a + different mechanism to prevent the crash, the test was failing even + though WebKit2 was not vulnerable to the crash. This new test crashes + if there is no mechanism in place to prevent it and passes in both + WebKit1 and WebKit2. + + Fixes <http://webkit.org/b/46711> <rdar://problem/8485903> + platform/win/plugins/plugin-delayed-destroy.html fails in WebKit2 + + Reviewed by Anders Carlsson. + + * DumpRenderTree/DumpRenderTree.xcodeproj/project.pbxproj: + * DumpRenderTree/TestNetscapePlugIn/win/TestNetscapePlugin.vcproj: + * DumpRenderTree/qt/TestNetscapePlugin/TestNetscapePlugin.pro: + * GNUmakefile.am: + Added new file. + + * DumpRenderTree/TestNetscapePlugIn/PluginObject.cpp: + (pluginDeallocate): Make sure we delete the PluginTest object. This + prevents a leak and also allows us to test the crash. + + * DumpRenderTree/TestNetscapePlugIn/PluginTest.cpp: + (PluginTest::executeScript): Made this into a non-static member + function. + + (PluginTest::waitUntilDone): + (PluginTest::notifyDone): + Updated for changes to executeScript. + + * DumpRenderTree/TestNetscapePlugIn/PluginTest.h: Added executeScript. + + * DumpRenderTree/TestNetscapePlugIn/Tests/EvaluateJSAfterRemovingPluginElement.cpp: Added. + (EvaluateJSAfterRemovingPluginElement::EvaluateJSAfterRemovingPluginElement): + Initialize ourselves and tell the test harness to wait. + (EvaluateJSAfterRemovingPluginElement::NPP_DestroyStream): Remove our + plugin element from the document, then execute some JavaScript. If + WebKit does not have appropriate mechanisms in place, we'll be + destroyed inside the first call to executeScript and crash on the + second call. + +2010-11-02 Stephen White <senorblanco@chromium.org> + + Reviewed by Tony Chang. + + [chromium] Fix LayoutTestController UMRs. + https://bugs.webkit.org/show_bug.cgi?id=48872 + + * DumpRenderTree/chromium/LayoutTestController.cpp: + (LayoutTestController::LayoutTestController): + +2010-11-03 Kent Tamura <tkent@chromium.org> + + Reviewed by Dimitri Glazkov. + + REGRESSION: rebaseline-chromium-webkit-tests uses non-zero tolerance for + image dup detection + https://bugs.webkit.org/show_bug.cgi?id=48744 + + * Scripts/webkitpy/layout_tests/rebaseline_chromium_webkit_tests.py: + - Make a function for option parsing for ease of test + - Set 0 to options.tolerance + * Scripts/webkitpy/layout_tests/rebaseline_chromium_webkit_tests_unittest.py: + - Add a test for this change + +2010-11-02 Gyuyoung Kim <gyuyoung.kim@samsung.com> + + Unreviewed: Add myself to the list of Committers. + + * Scripts/webkitpy/common/config/committers.py: + +2010-11-02 Anders Carlsson <andersca@apple.com> + + Fix build. + + * TestWebKitAPI/PlatformUtilities.cpp: + (TestWebKitAPI::Util::createContextForInjectedBundleTest): + +2010-11-02 Sam Weinig <sam@webkit.org> + + Reviewed by Anders Carlsson. + + Add a way to send startup messages on the context which can be posted when a process launches + <rdar://problem/8617928> + https://bugs.webkit.org/show_bug.cgi?id=48838 + + * MiniBrowser/mac/WebBundle/WebBundleMain.m: + (WKBundleInitialize): + * TestWebKitAPI/InjectedBundleController.cpp: + (TestWebKitAPI::InjectedBundleController::initialize): + (TestWebKitAPI::InjectedBundleController::didReceiveMessage): + * TestWebKitAPI/InjectedBundleController.h: + * TestWebKitAPI/InjectedBundleMain.cpp: + (WKBundleInitialize): + * TestWebKitAPI/PlatformUtilities.cpp: + (TestWebKitAPI::Util::createContextForInjectedBundleTest): + * WebKitTestRunner/InjectedBundle/InjectedBundleMain.cpp: + (WKBundleInitialize): + Update implementations of WKBundleInitialize to take an initial userData + argument. Change TestWebKitAPI to use the new initial userData to initialize + each test's bundle. + +2010-11-02 Benjamin Kalman <kalman@google.com> + + Reviewed by Ojan Vafai. + + new-run-webkit-tests doesn't strip "LayoutTests/" from prefix, unlike old-run-webkit-tests + https://bugs.webkit.org/show_bug.cgi?id=48794 + + * Scripts/webkitpy/layout_tests/run_webkit_tests.py: Strip the "LayoutTests/" prefix from test argument paths. + +2010-11-02 Adam Roben <aroben@apple.com> + + Skip webkitpy.layout_tests.run_webkit_tests_unittest.MainTest on Cygwin + Python 2.5.x + + It is known to hang on that version of Python. See + <http://webkit.org/b/48614>. + + Reviewed by Adam Barth. + + * Scripts/webkitpy/layout_tests/run_webkit_tests_unittest.py: Use + skip_if to skip MainTest on Cygwin Python 2.5.x. + + * Scripts/webkitpy/test/skip.py: Added. + (skip_if): If the passed-in condition is false, find all the test_* + methods of the given class and replace them with a function that just + logs that we're skipping these tests. This is loosely based on the + unittest.skip_if decorator added in Python 3.1. + (_skipped_method): Returns a function that just logs that the tests are + being skipped. This is used in place of the actual test_* functions. + + * Scripts/webkitpy/test/skip_unittest.py: Added. + (SkipTest.setUp): Create a logger for ourselves and give it a handler + that logs to a private stream. + (SkipTest.tearDown): Reset the logger. + (SkipTest.create_fixture_class): Returns a class that we use to test + skip_if. It has a single test_* method, test_foo, that just calls + through to a callback. + (SkipTest.foo_callback): Record that test_foo was called. + (SkipTest.test_skip_if_false): Pass skip_if a False condition and test + that test_foo does get called. + (SkipTest.test_skip_if_true): Pass skip_if a True condition and test + that test_foo does not get called and the appropriate message gets + logged. + +2010-11-02 Adam Barth <abarth@webkit.org> + + Reviewed by Eric Seidel. + + webkit-patch should tell check-webkit-style which files were changed so + check-webkit-style doesn't have to stat the whole working copy again + https://bugs.webkit.org/show_bug.cgi?id=48792 + + * Scripts/webkitpy/tool/mocktool.py: + * Scripts/webkitpy/tool/steps/checkstyle.py: + +2010-11-02 Robert Kroeger <rjkroege@chromium.org> + + Reviewed by James Robinson. + + [Chromium/DRT] Make EventSendingController honour leapForward for touch events. + https://bugs.webkit.org/show_bug.cgi?id=48777 + + * DumpRenderTree/chromium/EventSender.cpp: + (EventSender::sendCurrentTouchEvent): + +2010-11-02 Adam Roben <aroben@apple.com> + + Only track resource identifiers in DRT when dumpResourceLoadCallbacks + is on + + This reverts Windows to our pre-r71097 behavior. That patch made us + track all resource identifiers, including the main resource, so the + main resource's URL started appearing in test output instead of + "<unknown>". Arguably having the main resource's URL is better, but all + other platforms print "<unknown>" and we want to match. + + Fixes <http://webkit.org/b/48837> <rdar://problem/8620351> REGRESSION + (r71097): Many http tests failing on Windows + + Reviewed by Anders Carlsson. + + * DumpRenderTree/win/ResourceLoadDelegate.cpp: + (ResourceLoadDelegate::identifierForInitialRequest): Don't add the + identifier to the URL map if we're not supposed to dump resource load + callbacks. + (ResourceLoadDelegate::removeIdentifierForRequest): Always remove the + identifier from the URL map even if we're already "done". There's no + point in keeping out-of-date identifiers around. + +2010-11-01 Jenn Braithwaite <jennb@chromium.org> + + Reviewed by Adam Roben. + + Windows: Update resource tracking when moving a frame between documents + https://bugs.webkit.org/show_bug.cgi?id=48364 + + * DumpRenderTree/win/DumpRenderTree.cpp: + (createWebViewAndOffscreenWindow): + (main): + Give each WebView its own ResourceLoadDelegate instance in order to + make assertions about resource ids on a particular WebView. + * DumpRenderTree/win/ResourceLoadDelegate.cpp: + (ResourceLoadDelegate::identifierForInitialRequest): + Always add id to the map. + (ResourceLoadDelegate::removeIdentifierForRequest): + Added. + (ResourceLoadDelegate::willSendRequest): + (ResourceLoadDelegate::didReceiveAuthenticationChallenge): + (ResourceLoadDelegate::didReceiveResponse): + (ResourceLoadDelegate::didFinishLoadingFromDataSource): + (ResourceLoadDelegate::didFailLoadingWithError): + (ResourceLoadDelegate::descriptionSuitableForTestResult): + Replace static descriptionSuitableForTestResult with static member function to access identifier map. + * DumpRenderTree/win/ResourceLoadDelegate.h: + (ResourceLoadDelegate::urlMap): + Moved within class so that each WebView has its own id map. + +2010-11-01 Ojan Vafai <ojan@chromium.org> + + Reviewed by Dimitri Glazkov. + + remove debug code from run_webkit_tests.py + https://bugs.webkit.org/show_bug.cgi?id=48800 + + Remove temporary debug code and make --master-name required + if --test-results-server is set now that all clients set + --master-name. + + * Scripts/webkitpy/layout_tests/run_webkit_tests.py: + +2010-11-01 Tony Chang <tony@chromium.org> + + Reviewed by Kent Tamura. + + add plugin event logging for linux + https://bugs.webkit.org/show_bug.cgi?id=48779 + + This is taken from Chromium's fork of the layout test plugin: + http://git.chromium.org/gitweb/?p=chromium.git/.git;a=blob;f=webkit/tools/npapi_layout_test_plugin/main.cpp;h=3ebdada2f049b3624756438cff852364f86a2ede;hb=HEAD#l348 + + * DumpRenderTree/TestNetscapePlugIn/main.cpp: + (handleEventX11): + (NPP_HandleEvent): + +2010-11-01 Dirk Pranke <dpranke@chromium.org> + + Reviewed by James Robinson. + + new-run-webkit-tests: use DRT, child-processes=1 for GPU tests by default + https://bugs.webkit.org/show_bug.cgi?id=48790 + + * Scripts/webkitpy/layout_tests/port/chromium_gpu.py: + * Scripts/webkitpy/layout_tests/port/chromium_gpu_unittest.py: + +2010-11-01 Adam Barth <abarth@webkit.org> + + Reviewed by Eric Seidel. + + Teach check-webkit-style how to accept a list of files to diff on the + command line + https://bugs.webkit.org/show_bug.cgi?id=48784 + + In a future patch, webkit-patch will use this option to improve + performance. I'm landing this in two pieces to avoid causing a version + skew problem for the style-bot. + + * Scripts/check-webkit-style: + * Scripts/webkitpy/style/optparser.py: + * Scripts/webkitpy/style/optparser_unittest.py: + * Scripts/webkitpy/style_references.py: + +2010-11-01 Anders Carlsson <andersca@apple.com> + + Reviewed by John Sullivan. + + Tear down the related WebProcessProxy when a WebContext is deallocated + https://bugs.webkit.org/show_bug.cgi?id=48769 + + * TestWebKitAPI/Tests/WebKit2/FailedLoad.cpp: + (TestWebKitAPI::didFailProvisionalLoadWithErrorForFrame): + We don't support empty URLs anymore, update test to expect a null URL instead. + +2010-11-01 Søren Gjesse <sgjesse@chromium.org> + + Reviewed by Andreas Kling. + + Fix warning when compiling the chromium port of DumpRenderShell + with clang. + https://bugs.webkit.org/show_bug.cgi?id=48414 + + * DumpRenderTree/chromium/TestShell.h: + (TestShell::javaScriptFlagsForLoad): + +2010-11-01 Adam Roben <aroben@apple.com> + + Fix typo from r71022 + + * BuildSlaveSupport/build.webkit.org-config/config.json: + +2010-11-01 Adam Roben <aroben@apple.com> + + Trigger the Windows Release WebKit2 tests when a Release build + finishes, not when a Debug build finishes + + Fixes <http://webkit.org/b/48754> Windows Release WebKit2 tests are + triggered at the wrong time + + Reviewed by Sam Weinig. + + * BuildSlaveSupport/build.webkit.org-config/config.json: Fixed + triggerable name and trigger. + +2010-11-01 Mario Sanchez Prada <msanchez@igalia.com> + + Unreviewed. Adding my IRC nickname to the list of committers. + + * Scripts/webkitpy/common/config/committers.py: + +2010-10-31 Robert Hogan <robert@webkit.org> + + Reviewed by Antonio Gomes. + + [Qt] [Gtk] Plug-ins having upper case in mime type are failing to load + + Qt and Gtk are case-sensitive when storing the declared mime-type + of plugins. Since plugin mime-types are lowercased prior to searching + for them in the plugin database, ensure they are loaded with the + mime-type in lower case too. + + Change the test netscape plugin to declare its mimetype in sentence + case so that the correct behaviour is enforced. + + https://bugs.webkit.org/show_bug.cgi?id=36815 + + * DumpRenderTree/unix/TestNetscapePlugin/TestNetscapePlugin.cpp: + (NP_GetMIMEDescription): + +2010-10-31 Robert Hogan <robert@webkit.org> + + Reviewed by Antonio Gomes. + + [Qt] Support nodesFromRect in DRT + + https://bugs.webkit.org/show_bug.cgi?id=48716 + + * DumpRenderTree/qt/LayoutTestControllerQt.cpp: + (LayoutTestController::nodesFromRect): + * DumpRenderTree/qt/LayoutTestControllerQt.h: + +2010-10-30 Andreas Kling <kling@webkit.org> + + Reviewed by Antonio Gomes. + + [Qt] QtTestBrowser: Switching view type moves the embedded inspector + https://bugs.webkit.org/show_bug.cgi?id=48705 + + Reinsert the embedded inspector into the splitter after changing + between QWebView/QGraphicsWebView. + + * QtTestBrowser/launcherwindow.cpp: + (LauncherWindow::init): + (LauncherWindow::initializeView): + * QtTestBrowser/webinspector.h: + (WebInspector::WebInspector): + +2010-10-28 Antonio Gomes <agomes@rim.com> + + Reviewed by Ojan Vafai. + + Needs a "LinuxEditingBehavior", perhaps with a better name + https://bugs.webkit.org/show_bug.cgi?id=36627 + + Adding support to Mac's, GTK+'s, Windows' and Chromium's LayoutTestController class to test the newly introduced Unix editing behavior. + + * DumpRenderTree/chromium/LayoutTestController.cpp: + (LayoutTestController::setEditingBehavior): + * DumpRenderTree/gtk/LayoutTestControllerGtk.cpp: + (LayoutTestController::setEditingBehavior): + * DumpRenderTree/mac/LayoutTestControllerMac.mm: + (LayoutTestController::setEditingBehavior): + * DumpRenderTree/win/LayoutTestControllerWin.cpp: + (LayoutTestController::setEditingBehavior): + 2010-10-29 Andreas Kling <kling@webkit.org> Reviewed by Kenneth Rohde Christiansen. diff --git a/WebKitTools/DumpRenderTree/DumpRenderTree.xcodeproj/project.pbxproj b/WebKitTools/DumpRenderTree/DumpRenderTree.xcodeproj/project.pbxproj index bf0aebf..b2eb8e9 100644 --- a/WebKitTools/DumpRenderTree/DumpRenderTree.xcodeproj/project.pbxproj +++ b/WebKitTools/DumpRenderTree/DumpRenderTree.xcodeproj/project.pbxproj @@ -132,6 +132,7 @@ BCD08B710E1059D200A7D0C1 /* AccessibilityControllerMac.mm in Sources */ = {isa = PBXBuildFile; fileRef = BCD08B700E1059D200A7D0C1 /* AccessibilityControllerMac.mm */; }; BCF6C6500C98E9C000AC063E /* GCController.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BCF6C64F0C98E9C000AC063E /* GCController.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 */; }; E1B7816511AF31B7007E1BC2 /* MockGeolocationProvider.mm in Sources */ = {isa = PBXBuildFile; fileRef = E1B7808711AF1669007E1BC2 /* MockGeolocationProvider.mm */; }; E1B7816711AF31C3007E1BC2 /* MockGeolocationProvider.h in Headers */ = {isa = PBXBuildFile; fileRef = E1B7808511AF1643007E1BC2 /* MockGeolocationProvider.h */; }; @@ -307,6 +308,7 @@ 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>"; }; 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>"; }; E1B7808511AF1643007E1BC2 /* MockGeolocationProvider.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = MockGeolocationProvider.h; path = mac/MockGeolocationProvider.h; sourceTree = "<group>"; }; E1B7808711AF1669007E1BC2 /* MockGeolocationProvider.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = MockGeolocationProvider.mm; path = mac/MockGeolocationProvider.mm; sourceTree = "<group>"; }; @@ -462,6 +464,7 @@ isa = PBXGroup; children = ( 1A215A7511F26072008AD0F5 /* DocumentOpenInDestroyStream.cpp */, + C0E720741281C828004EF533 /* EvaluateJSAfterRemovingPluginElement.cpp */, 1A24BAA8120734EE00FBB059 /* NPRuntimeObjectFromDestroyedPlugin.cpp */, 1AC77DCE120605B6005C19EF /* NPRuntimeRemoveProperty.cpp */, C0EC3C9B12787F0500939164 /* NullNPPGetValuePointer.cpp */, @@ -751,6 +754,7 @@ 1A24BAA9120734EE00FBB059 /* NPRuntimeObjectFromDestroyedPlugin.cpp in Sources */, C06F9ABC1267A7060058E1F6 /* PassDifferentNPPStruct.cpp in Sources */, C0EC3C9C12787F0500939164 /* NullNPPGetValuePointer.cpp in Sources */, + C0E720751281C828004EF533 /* EvaluateJSAfterRemovingPluginElement.cpp in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/WebKitTools/DumpRenderTree/TestNetscapePlugIn/PluginObject.cpp b/WebKitTools/DumpRenderTree/TestNetscapePlugIn/PluginObject.cpp index db73a9d..7f1c4b4 100644 --- a/WebKitTools/DumpRenderTree/TestNetscapePlugIn/PluginObject.cpp +++ b/WebKitTools/DumpRenderTree/TestNetscapePlugIn/PluginObject.cpp @@ -27,13 +27,13 @@ #include "PluginObject.h" +#include "PluginTest.h" #include "TestObject.h" #include <assert.h> #include <stdarg.h> #include <stdio.h> - -#include <string.h> #include <stdlib.h> +#include <string.h> // Helper function which takes in the plugin window object for logging to the console object. static void pluginLogWithWindowObject(NPObject* windowObject, NPP instance, const char* message) @@ -118,10 +118,10 @@ static NPClass pluginClass = { pluginSetProperty, 0, // NPClass::removeProperty 0, // NPClass::enumerate - 0 // NPClass::construct + 0, // NPClass::construct }; -NPClass *getPluginClass(void) +NPClass* getPluginClass(void) { return &pluginClass; } @@ -176,6 +176,7 @@ enum { ID_TEST_GET_PROPERTY_RETURN_VALUE, ID_TEST_IDENTIFIER_TO_STRING, ID_TEST_IDENTIFIER_TO_INT, + ID_TEST_PASS_TEST_OBJECT, ID_TEST_POSTURL_FILE, ID_TEST_CONSTRUCT, ID_TEST_THROW_EXCEPTION_METHOD, @@ -212,6 +213,7 @@ static const NPUTF8 *pluginMethodIdentifierNames[NUM_METHOD_IDENTIFIERS] = { "testGetPropertyReturnValue", "testIdentifierToString", "testIdentifierToInt", + "testPassTestObject", "testPostURLFile", "testConstruct", "testThrowException", @@ -270,38 +272,48 @@ static bool pluginGetProperty(NPObject* obj, NPIdentifier name, NPVariant* resul strcpy(buf, originalString); STRINGZ_TO_NPVARIANT(buf, *result); return true; - } else if (name == pluginPropertyIdentifiers[ID_PROPERTY_EVENT_LOGGING]) { + } + if (name == pluginPropertyIdentifiers[ID_PROPERTY_EVENT_LOGGING]) { BOOLEAN_TO_NPVARIANT(plugin->eventLogging, *result); return true; - } else if (name == pluginPropertyIdentifiers[ID_PROPERTY_LOG_DESTROY]) { + } + if (name == pluginPropertyIdentifiers[ID_PROPERTY_LOG_DESTROY]) { BOOLEAN_TO_NPVARIANT(plugin->logDestroy, *result); return true; - } else if (name == pluginPropertyIdentifiers[ID_PROPERTY_HAS_STREAM]) { - BOOLEAN_TO_NPVARIANT(plugin->stream != 0, *result); + } + if (name == pluginPropertyIdentifiers[ID_PROPERTY_HAS_STREAM]) { + BOOLEAN_TO_NPVARIANT(plugin->stream, *result); return true; - } else if (name == pluginPropertyIdentifiers[ID_PROPERTY_TEST_OBJECT]) { + } + if (name == pluginPropertyIdentifiers[ID_PROPERTY_TEST_OBJECT]) { NPObject* testObject = plugin->testObject; browser->retainobject(testObject); OBJECT_TO_NPVARIANT(testObject, *result); return true; - } else if (name == pluginPropertyIdentifiers[ID_PROPERTY_RETURN_ERROR_FROM_NEWSTREAM]) { + } + if (name == pluginPropertyIdentifiers[ID_PROPERTY_RETURN_ERROR_FROM_NEWSTREAM]) { BOOLEAN_TO_NPVARIANT(plugin->returnErrorFromNewStream, *result); return true; - } else if (name == pluginPropertyIdentifiers[ID_PROPERTY_RETURN_NEGATIVE_ONE_FROM_WRITE]) { + } + if (name == pluginPropertyIdentifiers[ID_PROPERTY_RETURN_NEGATIVE_ONE_FROM_WRITE]) { BOOLEAN_TO_NPVARIANT(plugin->returnNegativeOneFromWrite, *result); return true; - } else if (name == pluginPropertyIdentifiers[ID_PROPERTY_PRIVATE_BROWSING_ENABLED]) { + } + if (name == pluginPropertyIdentifiers[ID_PROPERTY_PRIVATE_BROWSING_ENABLED]) { NPBool privateBrowsingEnabled = FALSE; browser->getvalue(plugin->npp, NPNVprivateModeBool, &privateBrowsingEnabled); BOOLEAN_TO_NPVARIANT(privateBrowsingEnabled, *result); return true; - } else if (name == pluginPropertyIdentifiers[ID_PROPERTY_CACHED_PRIVATE_BROWSING_ENABLED]) { + } + if (name == pluginPropertyIdentifiers[ID_PROPERTY_CACHED_PRIVATE_BROWSING_ENABLED]) { BOOLEAN_TO_NPVARIANT(plugin->cachedPrivateBrowsingMode, *result); return true; - } else if (name == pluginPropertyIdentifiers[ID_PROPERTY_THROW_EXCEPTION_PROPERTY]) { + } + if (name == pluginPropertyIdentifiers[ID_PROPERTY_THROW_EXCEPTION_PROPERTY]) { browser->setexception(obj, "plugin object testThrowExceptionProperty SUCCESS"); return true; - } else if (name == pluginPropertyIdentifiers[ID_LAST_SET_WINDOW_ARGUMENTS]) { + } + if (name == pluginPropertyIdentifiers[ID_LAST_SET_WINDOW_ARGUMENTS]) { char* buf = static_cast<char*>(browser->memalloc(256)); snprintf(buf, 256, "x: %d, y: %d, width: %u, height: %u, clipRect: (%u, %u, %u, %u)", (int)plugin->lastWindow.x, (int)plugin->lastWindow.y, (unsigned)plugin->lastWindow.width, (unsigned)plugin->lastWindow.height, plugin->lastWindow.clipRect.left, plugin->lastWindow.clipRect.top, plugin->lastWindow.clipRect.right - plugin->lastWindow.clipRect.left, plugin->lastWindow.clipRect.bottom - plugin->lastWindow.clipRect.top); @@ -319,19 +331,24 @@ static bool pluginSetProperty(NPObject* obj, NPIdentifier name, const NPVariant* if (name == pluginPropertyIdentifiers[ID_PROPERTY_EVENT_LOGGING]) { plugin->eventLogging = NPVARIANT_TO_BOOLEAN(*variant); return true; - } else if (name == pluginPropertyIdentifiers[ID_PROPERTY_LOG_DESTROY]) { + } + if (name == pluginPropertyIdentifiers[ID_PROPERTY_LOG_DESTROY]) { plugin->logDestroy = NPVARIANT_TO_BOOLEAN(*variant); return true; - } else if (name == pluginPropertyIdentifiers[ID_PROPERTY_RETURN_ERROR_FROM_NEWSTREAM]) { + } + if (name == pluginPropertyIdentifiers[ID_PROPERTY_RETURN_ERROR_FROM_NEWSTREAM]) { plugin->returnErrorFromNewStream = NPVARIANT_TO_BOOLEAN(*variant); return true; - } else if (name == pluginPropertyIdentifiers[ID_PROPERTY_RETURN_NEGATIVE_ONE_FROM_WRITE]) { + } + if (name == pluginPropertyIdentifiers[ID_PROPERTY_RETURN_NEGATIVE_ONE_FROM_WRITE]) { plugin->returnNegativeOneFromWrite = NPVARIANT_TO_BOOLEAN(*variant); return true; - } else if (name == pluginPropertyIdentifiers[ID_PROPERTY_THROW_EXCEPTION_PROPERTY]) { + } + if (name == pluginPropertyIdentifiers[ID_PROPERTY_THROW_EXCEPTION_PROPERTY]) { browser->setexception(obj, "plugin object testThrowExceptionProperty SUCCESS"); return true; - } else if (name == pluginPropertyIdentifiers[ID_PROPERTY_WINDOWED_PLUGIN]) { + } + if (name == pluginPropertyIdentifiers[ID_PROPERTY_WINDOWED_PLUGIN]) { browser->setvalue(plugin->npp, NPPVpluginWindowBool, (void *)NPVARIANT_TO_BOOLEAN(*variant)); return true; } @@ -391,9 +408,9 @@ static NPIdentifier variantToIdentifier(NPVariant variant) { if (NPVARIANT_IS_STRING(variant)) return stringVariantToIdentifier(variant); - else if (NPVARIANT_IS_INT32(variant)) + if (NPVARIANT_IS_INT32(variant)) return int32VariantToIdentifier(variant); - else if (NPVARIANT_IS_DOUBLE(variant)) + if (NPVARIANT_IS_DOUBLE(variant)) return doubleVariantToIdentifier(variant); return 0; } @@ -424,9 +441,29 @@ static bool testIdentifierToInt(PluginObject*, const NPVariant* args, uint32_t a return true; } +static bool testPassTestObject(PluginObject* obj, const NPVariant* args, uint32_t argCount, NPVariant* result) +{ + if (argCount != 2 || !NPVARIANT_IS_STRING(args[0])) + return false; + + NPObject* windowScriptObject; + browser->getvalue(obj->npp, NPNVWindowNPObject, &windowScriptObject); + + NPUTF8* callbackString = createCStringFromNPVariant(&args[0]); + NPIdentifier callbackIdentifier = browser->getstringidentifier(callbackString); + free(callbackString); + + NPVariant browserResult; + browser->invoke(obj->npp, windowScriptObject, callbackIdentifier, &args[1], 1, &browserResult); + browser->releasevariantvalue(&browserResult); + + VOID_TO_NPVARIANT(*result); + return true; +} + static bool testCallback(PluginObject* obj, const NPVariant* args, uint32_t argCount, NPVariant* result) { - if (argCount == 0 || !NPVARIANT_IS_STRING(args[0])) + if (!argCount || !NPVARIANT_IS_STRING(args[0])) return false; NPObject* windowScriptObject; @@ -457,7 +494,8 @@ static bool getURL(PluginObject* obj, const NPVariant* args, uint32_t argCount, INT32_TO_NPVARIANT(npErr, *result); return true; - } else if (argCount == 1 && NPVARIANT_IS_STRING(args[0])) { + } + if (argCount == 1 && NPVARIANT_IS_STRING(args[0])) { NPUTF8* urlString = createCStringFromNPVariant(&args[0]); NPError npErr = browser->geturl(obj->npp, urlString, 0); free(urlString); @@ -476,7 +514,7 @@ static bool getURLNotify(PluginObject* obj, const NPVariant* args, uint32_t argC return false; NPUTF8* urlString = createCStringFromNPVariant(&args[0]); - NPUTF8* targetString = (NPVARIANT_IS_STRING(args[1]) ? createCStringFromNPVariant(&args[1]) : NULL); + NPUTF8* targetString = (NPVARIANT_IS_STRING(args[1]) ? createCStringFromNPVariant(&args[1]) : 0); NPUTF8* callbackString = createCStringFromNPVariant(&args[2]); NPIdentifier callbackIdentifier = browser->getstringidentifier(callbackString); @@ -495,7 +533,7 @@ static bool testInvokeDefault(PluginObject* obj, const NPVariant* args, uint32_t if (!NPVARIANT_IS_OBJECT(args[0])) return false; - NPObject *callback = NPVARIANT_TO_OBJECT(args[0]); + NPObject* callback = NPVARIANT_TO_OBJECT(args[0]); NPVariant invokeArgs[1]; NPVariant browserResult; @@ -568,10 +606,10 @@ static bool testGetIntIdentifier(PluginObject*, const NPVariant* args, uint32_t static bool testGetProperty(PluginObject* obj, const NPVariant* args, uint32_t argCount, NPVariant* result) { - if (argCount == 0) + if (!argCount) return false; - NPObject *object; + NPObject* object; browser->getvalue(obj->npp, NPNVWindowNPObject, &object); for (uint32_t i = 0; i < argCount; i++) { @@ -730,7 +768,7 @@ bool testDocumentOpen(NPP npp) NPIdentifier documentId = browser->getstringidentifier("document"); NPIdentifier openId = browser->getstringidentifier("open"); - NPObject *windowObject = NULL; + NPObject* windowObject = 0; browser->getvalue(npp, NPNVWindowNPObject, &windowObject); if (!windowObject) return false; @@ -742,7 +780,7 @@ bool testDocumentOpen(NPP npp) return false; } - NPObject *documentObject = NPVARIANT_TO_OBJECT(docVariant); + NPObject* documentObject = NPVARIANT_TO_OBJECT(docVariant); NPVariant openArgs[2]; STRINGZ_TO_NPVARIANT("text/html", openArgs[0]); @@ -774,7 +812,7 @@ bool testWindowOpen(NPP npp) { NPIdentifier openId = browser->getstringidentifier("open"); - NPObject *windowObject = NULL; + NPObject* windowObject = 0; browser->getvalue(npp, NPNVWindowNPObject, &windowObject); if (!windowObject) return false; @@ -856,87 +894,100 @@ static bool pluginInvoke(NPObject* header, NPIdentifier name, const NPVariant* a PluginObject* plugin = reinterpret_cast<PluginObject*>(header); if (name == pluginMethodIdentifiers[ID_TEST_CALLBACK_METHOD]) return testCallback(plugin, args, argCount, result); - else if (name == pluginMethodIdentifiers[ID_TEST_GETURL]) + if (name == pluginMethodIdentifiers[ID_TEST_GETURL]) return getURL(plugin, args, argCount, result); - else if (name == pluginMethodIdentifiers[ID_TEST_DOM_ACCESS]) + if (name == pluginMethodIdentifiers[ID_TEST_DOM_ACCESS]) return testDOMAccess(plugin, args, argCount, result); - else if (name == pluginMethodIdentifiers[ID_TEST_GET_URL_NOTIFY]) + if (name == pluginMethodIdentifiers[ID_TEST_GET_URL_NOTIFY]) return getURLNotify(plugin, args, argCount, result); - else if (name == pluginMethodIdentifiers[ID_TEST_INVOKE_DEFAULT]) + if (name == pluginMethodIdentifiers[ID_TEST_INVOKE_DEFAULT]) return testInvokeDefault(plugin, args, argCount, result); - else if (name == pluginMethodIdentifiers[ID_TEST_ENUMERATE]) + if (name == pluginMethodIdentifiers[ID_TEST_ENUMERATE]) return testEnumerate(plugin, args, argCount, result); - else if (name == pluginMethodIdentifiers[ID_DESTROY_STREAM]) + if (name == pluginMethodIdentifiers[ID_DESTROY_STREAM]) return destroyStream(plugin, args, argCount, result); - else if (name == pluginMethodIdentifiers[ID_TEST_GETINTIDENTIFIER]) + if (name == pluginMethodIdentifiers[ID_TEST_GETINTIDENTIFIER]) return testGetIntIdentifier(plugin, args, argCount, result); - else if (name == pluginMethodIdentifiers[ID_TEST_EVALUATE]) + if (name == pluginMethodIdentifiers[ID_TEST_EVALUATE]) return testEvaluate(plugin, args, argCount, result); - else if (name == pluginMethodIdentifiers[ID_TEST_GET_PROPERTY]) + if (name == pluginMethodIdentifiers[ID_TEST_GET_PROPERTY]) return testGetProperty(plugin, args, argCount, result); - else if (name == pluginMethodIdentifiers[ID_TEST_GET_PROPERTY_RETURN_VALUE]) + if (name == pluginMethodIdentifiers[ID_TEST_GET_PROPERTY_RETURN_VALUE]) return testGetPropertyReturnValue(plugin, args, argCount, result); - else if (name == pluginMethodIdentifiers[ID_TEST_HAS_PROPERTY]) + if (name == pluginMethodIdentifiers[ID_TEST_HAS_PROPERTY]) return testHasProperty(plugin, args, argCount, result); - else if (name == pluginMethodIdentifiers[ID_TEST_HAS_METHOD]) + if (name == pluginMethodIdentifiers[ID_TEST_HAS_METHOD]) return testHasMethod(plugin, args, argCount, result); - else if (name == pluginMethodIdentifiers[ID_TEST_IDENTIFIER_TO_STRING]) + if (name == pluginMethodIdentifiers[ID_TEST_IDENTIFIER_TO_STRING]) return testIdentifierToString(plugin, args, argCount, result); - else if (name == pluginMethodIdentifiers[ID_TEST_IDENTIFIER_TO_INT]) + if (name == pluginMethodIdentifiers[ID_TEST_IDENTIFIER_TO_INT]) return testIdentifierToInt(plugin, args, argCount, result); - else if (name == pluginMethodIdentifiers[ID_TEST_POSTURL_FILE]) + if (name == pluginMethodIdentifiers[ID_TEST_PASS_TEST_OBJECT]) + return testPassTestObject(plugin, args, argCount, result); + if (name == pluginMethodIdentifiers[ID_TEST_POSTURL_FILE]) return testPostURLFile(plugin, args, argCount, result); - else if (name == pluginMethodIdentifiers[ID_TEST_CONSTRUCT]) + if (name == pluginMethodIdentifiers[ID_TEST_CONSTRUCT]) return testConstruct(plugin, args, argCount, result); - else if (name == pluginMethodIdentifiers[ID_TEST_THROW_EXCEPTION_METHOD]) { + if (name == pluginMethodIdentifiers[ID_TEST_THROW_EXCEPTION_METHOD]) { browser->setexception(header, "plugin object testThrowException SUCCESS"); return true; - } else if (name == pluginMethodIdentifiers[ID_TEST_FAIL_METHOD]) { + } + if (name == pluginMethodIdentifiers[ID_TEST_FAIL_METHOD]) { NPObject* windowScriptObject; browser->getvalue(plugin->npp, NPNVWindowNPObject, &windowScriptObject); browser->invoke(plugin->npp, windowScriptObject, name, args, argCount, result); - } else if (name == pluginMethodIdentifiers[ID_DESTROY_NULL_STREAM]) + return false; + } + if (name == pluginMethodIdentifiers[ID_DESTROY_NULL_STREAM]) return destroyNullStream(plugin, args, argCount, result); - else if (name == pluginMethodIdentifiers[ID_TEST_RELOAD_PLUGINS_NO_PAGES]) { + if (name == pluginMethodIdentifiers[ID_TEST_RELOAD_PLUGINS_NO_PAGES]) { browser->reloadplugins(false); return true; - } else if (name == pluginMethodIdentifiers[ID_TEST_RELOAD_PLUGINS_AND_PAGES]) { + } + if (name == pluginMethodIdentifiers[ID_TEST_RELOAD_PLUGINS_AND_PAGES]) { browser->reloadplugins(true); return true; - } else if (name == pluginMethodIdentifiers[ID_TEST_GET_BROWSER_PROPERTY]) { + } + if (name == pluginMethodIdentifiers[ID_TEST_GET_BROWSER_PROPERTY]) { browser->getproperty(plugin->npp, NPVARIANT_TO_OBJECT(args[0]), stringVariantToIdentifier(args[1]), result); return true; - } else if (name == pluginMethodIdentifiers[ID_TEST_SET_BROWSER_PROPERTY]) { + } + if (name == pluginMethodIdentifiers[ID_TEST_SET_BROWSER_PROPERTY]) { browser->setproperty(plugin->npp, NPVARIANT_TO_OBJECT(args[0]), stringVariantToIdentifier(args[1]), &args[2]); return true; - } else if (name == pluginMethodIdentifiers[ID_REMEMBER]) { + } + if (name == pluginMethodIdentifiers[ID_REMEMBER]) { if (plugin->rememberedObject) browser->releaseobject(plugin->rememberedObject); plugin->rememberedObject = NPVARIANT_TO_OBJECT(args[0]); browser->retainobject(plugin->rememberedObject); VOID_TO_NPVARIANT(*result); return true; - } else if (name == pluginMethodIdentifiers[ID_GET_REMEMBERED_OBJECT]) { + } + if (name == pluginMethodIdentifiers[ID_GET_REMEMBERED_OBJECT]) { assert(plugin->rememberedObject); browser->retainobject(plugin->rememberedObject); OBJECT_TO_NPVARIANT(plugin->rememberedObject, *result); return true; - } else if (name == pluginMethodIdentifiers[ID_GET_AND_FORGET_REMEMBERED_OBJECT]) { + } + if (name == pluginMethodIdentifiers[ID_GET_AND_FORGET_REMEMBERED_OBJECT]) { assert(plugin->rememberedObject); OBJECT_TO_NPVARIANT(plugin->rememberedObject, *result); plugin->rememberedObject = 0; return true; - } else if (name == pluginMethodIdentifiers[ID_REF_COUNT]) { + } + if (name == pluginMethodIdentifiers[ID_REF_COUNT]) { uint32_t refCount = NPVARIANT_TO_OBJECT(args[0])->referenceCount; INT32_TO_NPVARIANT(refCount, *result); return true; - } else if (name == pluginMethodIdentifiers[ID_SET_STATUS]) + } + if (name == pluginMethodIdentifiers[ID_SET_STATUS]) return testSetStatus(plugin, args, argCount, result); - else if (name == pluginMethodIdentifiers[ID_RESIZE_TO]) + if (name == pluginMethodIdentifiers[ID_RESIZE_TO]) return testResizeTo(plugin, args, argCount, result); - else if (name == pluginMethodIdentifiers[ID_NORMALIZE]) + if (name == pluginMethodIdentifiers[ID_NORMALIZE]) return normalizeOverride(plugin, args, argCount, result); - + return false; } @@ -990,6 +1041,7 @@ static NPObject *pluginAllocate(NPP npp, NPClass *theClass) static void pluginDeallocate(NPObject* header) { PluginObject* plugin = reinterpret_cast<PluginObject*>(header); + delete plugin->pluginTest; if (plugin->testObject) browser->releaseobject(plugin->testObject); if (plugin->rememberedObject) @@ -1008,14 +1060,14 @@ void handleCallback(PluginObject* object, const char *url, NPReason reason, void NPVariant args[2]; - NPObject *windowScriptObject; + NPObject* windowScriptObject; browser->getvalue(object->npp, NPNVWindowNPObject, &windowScriptObject); NPIdentifier callbackIdentifier = notifyData; INT32_TO_NPVARIANT(reason, args[0]); - char *strHdr = NULL; + char* strHdr = 0; if (object->firstUrl && object->firstHeaders && object->lastUrl && object->lastHeaders) { // Format expected by JavaScript validator: four fields separated by \n\n: // First URL; first header block; last URL; last header block. @@ -1040,7 +1092,7 @@ void handleCallback(PluginObject* object, const char *url, NPReason reason, void void notifyStream(PluginObject* object, const char *url, const char *headers) { - if (object->firstUrl == NULL) { + if (!object->firstUrl) { if (url) object->firstUrl = strdup(url); if (headers) @@ -1048,8 +1100,8 @@ void notifyStream(PluginObject* object, const char *url, const char *headers) } else { free(object->lastUrl); free(object->lastHeaders); - object->lastUrl = (url ? strdup(url) : NULL); - object->lastHeaders = (headers ? strdup(headers) : NULL); + object->lastUrl = (url ? strdup(url) : 0); + object->lastHeaders = (headers ? strdup(headers) : 0); } } diff --git a/WebKitTools/DumpRenderTree/TestNetscapePlugIn/PluginObject.h b/WebKitTools/DumpRenderTree/TestNetscapePlugIn/PluginObject.h index 99d5bf6..def8ad8 100644 --- a/WebKitTools/DumpRenderTree/TestNetscapePlugIn/PluginObject.h +++ b/WebKitTools/DumpRenderTree/TestNetscapePlugIn/PluginObject.h @@ -23,6 +23,9 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +#ifndef PluginObject_h +#define PluginObject_h + #include <WebKit/npfunctions.h> #if defined(XP_MACOSX) @@ -90,3 +93,4 @@ extern bool testWindowOpen(NPP npp); extern void* createCoreAnimationLayer(); #endif +#endif // PluginObject_h diff --git a/WebKitTools/DumpRenderTree/TestNetscapePlugIn/PluginTest.cpp b/WebKitTools/DumpRenderTree/TestNetscapePlugIn/PluginTest.cpp index e41e6e5..06c9953 100644 --- a/WebKitTools/DumpRenderTree/TestNetscapePlugIn/PluginTest.cpp +++ b/WebKitTools/DumpRenderTree/TestNetscapePlugIn/PluginTest.cpp @@ -101,28 +101,28 @@ bool PluginTest::NPN_RemoveProperty(NPObject* npObject, NPIdentifier propertyNam return browser->removeproperty(m_npp, npObject, propertyName); } -static void executeScript(NPP npp, const char* script) +void PluginTest::executeScript(const char* script) { NPObject* windowScriptObject; - browser->getvalue(npp, NPNVWindowNPObject, &windowScriptObject); + browser->getvalue(m_npp, NPNVWindowNPObject, &windowScriptObject); NPString npScript; npScript.UTF8Characters = script; npScript.UTF8Length = strlen(script); NPVariant browserResult; - browser->evaluate(npp, windowScriptObject, &npScript, &browserResult); + browser->evaluate(m_npp, windowScriptObject, &npScript, &browserResult); browser->releasevariantvalue(&browserResult); } void PluginTest::waitUntilDone() { - executeScript(m_npp, "layoutTestController.waitUntilDone()"); + executeScript("layoutTestController.waitUntilDone()"); } void PluginTest::notifyDone() { - executeScript(m_npp, "layoutTestController.notifyDone()"); + executeScript("layoutTestController.notifyDone()"); } void PluginTest::registerCreateTestFunction(const string& identifier, CreateTestFunction createTestFunction) diff --git a/WebKitTools/DumpRenderTree/TestNetscapePlugIn/PluginTest.h b/WebKitTools/DumpRenderTree/TestNetscapePlugIn/PluginTest.h index 0497764..ae9bd82 100644 --- a/WebKitTools/DumpRenderTree/TestNetscapePlugIn/PluginTest.h +++ b/WebKitTools/DumpRenderTree/TestNetscapePlugIn/PluginTest.h @@ -68,6 +68,8 @@ public: NPObject* NPN_CreateObject(NPClass*); bool NPN_RemoveProperty(NPObject*, NPIdentifier propertyName); + void executeScript(const char*); + template<typename TestClassTy> class Register { public: Register(const std::string& identifier) diff --git a/WebKitTools/DumpRenderTree/TestNetscapePlugIn/TestObject.cpp b/WebKitTools/DumpRenderTree/TestNetscapePlugIn/TestObject.cpp index 0b32191..8946c0e 100644 --- a/WebKitTools/DumpRenderTree/TestNetscapePlugIn/TestObject.cpp +++ b/WebKitTools/DumpRenderTree/TestNetscapePlugIn/TestObject.cpp @@ -59,18 +59,29 @@ NPClass *getTestClass(void) return &testClass; } -static bool identifiersInitialized = false; +typedef struct { + NPObject header; + NPObject* testObject; +} TestObject; -#define ID_OBJECT_POINTER 2 +static bool identifiersInitialized = false; #define NUM_ENUMERATABLE_TEST_IDENTIFIERS 2 -#define NUM_TEST_IDENTIFIERS 3 + +enum { + ID_PROPERTY_FOO = 0, + ID_PROPERTY_BAR, + ID_PROPERTY_OBJECT_POINTER, + ID_PROPERTY_TEST_OBJECT, + NUM_TEST_IDENTIFIERS, +}; static NPIdentifier testIdentifiers[NUM_TEST_IDENTIFIERS]; static const NPUTF8 *testIdentifierNames[NUM_TEST_IDENTIFIERS] = { "foo", "bar", "objectPointer", + "testObject", }; #define ID_THROW_EXCEPTION_METHOD 0 @@ -87,20 +98,24 @@ static void initializeIdentifiers(void) browser->getstringidentifiers(testMethodIdentifierNames, NUM_METHOD_IDENTIFIERS, testMethodIdentifiers); } -static NPObject *testAllocate(NPP /*npp*/, NPClass* /*theClass*/) +static NPObject* testAllocate(NPP /*npp*/, NPClass* /*theClass*/) { - NPObject *newInstance = static_cast<NPObject*>(malloc(sizeof(NPObject))); - + TestObject* newInstance = static_cast<TestObject*>(malloc(sizeof(TestObject))); + newInstance->testObject = 0; + if (!identifiersInitialized) { identifiersInitialized = true; initializeIdentifiers(); } - - return newInstance; + + return reinterpret_cast<NPObject*>(newInstance); } static void testDeallocate(NPObject *obj) { + TestObject* testObject = reinterpret_cast<TestObject*>(obj); + if (testObject->testObject) + browser->releaseobject(testObject->testObject); free(obj); } @@ -134,17 +149,30 @@ static bool testHasProperty(NPObject*, NPIdentifier name) static bool testGetProperty(NPObject* npobj, NPIdentifier name, NPVariant* result) { - if (name == testIdentifiers[ID_OBJECT_POINTER]) { + if (name == testIdentifiers[ID_PROPERTY_FOO]) { + char* mem = static_cast<char*>(browser->memalloc(4)); + strcpy(mem, "foo"); + STRINGZ_TO_NPVARIANT(mem, *result); + return true; + } + if (name == testIdentifiers[ID_PROPERTY_OBJECT_POINTER]) { int32_t objectPointer = static_cast<int32_t>(reinterpret_cast<long long>(npobj)); INT32_TO_NPVARIANT(objectPointer, *result); return true; } + if (name == testIdentifiers[ID_PROPERTY_TEST_OBJECT]) { + TestObject* testObject = reinterpret_cast<TestObject*>(npobj); + if (!testObject->testObject) + testObject->testObject = browser->createobject(0, &testClass); + browser->retainobject(testObject->testObject); + OBJECT_TO_NPVARIANT(testObject->testObject, *result); + return true; + } return false; } - static bool testEnumerate(NPObject* /*npobj*/, NPIdentifier **value, uint32_t *count) { *count = NUM_ENUMERATABLE_TEST_IDENTIFIERS; @@ -163,5 +191,3 @@ static bool testConstruct(NPObject* npobj, const NPVariant* /*args*/, uint32_t / OBJECT_TO_NPVARIANT(npobj, *result); return true; } - - diff --git a/WebKitTools/DumpRenderTree/TestNetscapePlugIn/Tests/EvaluateJSAfterRemovingPluginElement.cpp b/WebKitTools/DumpRenderTree/TestNetscapePlugIn/Tests/EvaluateJSAfterRemovingPluginElement.cpp new file mode 100644 index 0000000..4b5d3e0 --- /dev/null +++ b/WebKitTools/DumpRenderTree/TestNetscapePlugIn/Tests/EvaluateJSAfterRemovingPluginElement.cpp @@ -0,0 +1,64 @@ +/* + * 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" + +#include "PluginObject.h" + +using namespace std; + +// Executing JS after removing the plugin element from the document should not crash. + +class EvaluateJSAfterRemovingPluginElement : public PluginTest { +public: + EvaluateJSAfterRemovingPluginElement(NPP, const string& identifier); + +private: + virtual NPError NPP_DestroyStream(NPStream*, NPReason); + + bool m_didExecuteScript; +}; + +static PluginTest::Register<EvaluateJSAfterRemovingPluginElement> registrar("evaluate-js-after-removing-plugin-element"); + +EvaluateJSAfterRemovingPluginElement::EvaluateJSAfterRemovingPluginElement(NPP npp, const string& identifier) + : PluginTest(npp, identifier) + , m_didExecuteScript(false) +{ + waitUntilDone(); +} + +NPError EvaluateJSAfterRemovingPluginElement::NPP_DestroyStream(NPStream*, NPReason) +{ + if (m_didExecuteScript) + return NPERR_NO_ERROR; + m_didExecuteScript = true; + + executeScript("var plugin = document.getElementsByTagName('embed')[0]; plugin.parentElement.removeChild(plugin);"); + executeScript("document.body.appendChild(document.createTextNode('Executing script after removing the plugin element from the document succeeded.'));"); + notifyDone(); + + return NPERR_NO_ERROR; +} diff --git a/WebKitTools/DumpRenderTree/TestNetscapePlugIn/Tests/win/DrawsGradient.cpp b/WebKitTools/DumpRenderTree/TestNetscapePlugIn/Tests/win/DrawsGradient.cpp new file mode 100644 index 0000000..2b06198 --- /dev/null +++ b/WebKitTools/DumpRenderTree/TestNetscapePlugIn/Tests/win/DrawsGradient.cpp @@ -0,0 +1,118 @@ +/* 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 "WindowedPluginTest.h" + +#include "PluginObject.h" + +using namespace std; + +// Just fills its window with some gradients + +class DrawsGradient : public WindowedPluginTest { +public: + DrawsGradient(NPP, const string& identifier); + +private: + void paint(HDC) const; + + LRESULT onPaint(WPARAM, LPARAM, bool& handled); + LRESULT onPrintClient(WPARAM, LPARAM, bool& handled); + + virtual LRESULT wndProc(UINT message, WPARAM, LPARAM, bool& handled); +}; + +static PluginTest::Register<DrawsGradient> registrar("draws-gradient"); + +DrawsGradient::DrawsGradient(NPP npp, const string& identifier) + : WindowedPluginTest(npp, identifier) +{ +} + +LRESULT DrawsGradient::wndProc(UINT message, WPARAM wParam, LPARAM lParam, bool& handled) +{ + LRESULT result = 0; + + switch (message) { + case WM_PAINT: + result = onPaint(wParam, lParam, handled); + break; + case WM_PRINTCLIENT: + result = onPrintClient(wParam, lParam, handled); + break; + default: + handled = false; + } + + return result; +} + +LRESULT DrawsGradient::onPaint(WPARAM, LPARAM, bool& handled) +{ + PAINTSTRUCT paintStruct; + HDC dc = ::BeginPaint(window(), &paintStruct); + if (!dc) + return 0; + + paint(dc); + ::EndPaint(window(), &paintStruct); + + handled = true; + return 0; +} + +LRESULT DrawsGradient::onPrintClient(WPARAM wParam, LPARAM, bool& handled) +{ + paint(reinterpret_cast<HDC>(wParam)); + + handled = true; + return 0; +} + +void DrawsGradient::paint(HDC dc) const +{ + RECT clientRect; + if (!::GetClientRect(window(), &clientRect)) + return; + + TRIVERTEX vertices[] = { + // Upper-left: green + { clientRect.left, clientRect.top, 0, 0xff00, 0, 0 }, + // Upper-right: blue + { clientRect.right, clientRect.top, 0, 0, 0xff00, 0 }, + // Lower-left: yellow + { clientRect.left, clientRect.bottom, 0xff00, 0xff00, 0, 0 }, + // Lower-right: red + { clientRect.right, clientRect.bottom, 0xff00, 0, 0, 0 }, + }; + + GRADIENT_TRIANGLE mesh[] = { + // Upper-left triangle + { 0, 1, 2 }, + // Lower-right triangle + { 1, 2, 3 }, + }; + + ::GradientFill(dc, vertices, _countof(vertices), mesh, _countof(mesh), GRADIENT_FILL_TRIANGLE); +} diff --git a/WebKitTools/DumpRenderTree/TestNetscapePlugIn/Tests/win/NPNInvalidateRectInvalidatesWindow.cpp b/WebKitTools/DumpRenderTree/TestNetscapePlugIn/Tests/win/NPNInvalidateRectInvalidatesWindow.cpp index 90ea54d..e598c49 100644 --- a/WebKitTools/DumpRenderTree/TestNetscapePlugIn/Tests/win/NPNInvalidateRectInvalidatesWindow.cpp +++ b/WebKitTools/DumpRenderTree/TestNetscapePlugIn/Tests/win/NPNInvalidateRectInvalidatesWindow.cpp @@ -23,7 +23,7 @@ * THE POSSIBILITY OF SUCH DAMAGE. */ -#include "PluginTest.h" +#include "WindowedPluginTest.h" #include "PluginObject.h" @@ -69,28 +69,24 @@ TemporaryWindowMover::~TemporaryWindowMover() ::SetWindowPos(m_window, 0, m_savedWindowRect.left, m_savedWindowRect.top, 0, 0, SWP_HIDEWINDOW | standardSetWindowPosFlags); } -class NPNInvalidateRectInvalidatesWindow : public PluginTest { +class NPNInvalidateRectInvalidatesWindow : public WindowedPluginTest { public: NPNInvalidateRectInvalidatesWindow(NPP, const string& identifier); ~NPNInvalidateRectInvalidatesWindow(); private: - static LRESULT CALLBACK wndProc(HWND, UINT message, WPARAM, LPARAM); + virtual LRESULT wndProc(UINT message, WPARAM, LPARAM, bool& handled); void onPaint(); void testInvalidateRect(); virtual NPError NPP_SetWindow(NPP, NPWindow*); - HWND m_window; - WNDPROC m_originalWndProc; TemporaryWindowMover* m_windowMover; }; NPNInvalidateRectInvalidatesWindow::NPNInvalidateRectInvalidatesWindow(NPP npp, const string& identifier) - : PluginTest(npp, identifier) - , m_window(0) - , m_originalWndProc(0) + : WindowedPluginTest(npp, identifier) , m_windowMover(0) { } @@ -100,30 +96,20 @@ NPNInvalidateRectInvalidatesWindow::~NPNInvalidateRectInvalidatesWindow() delete m_windowMover; } -NPError NPNInvalidateRectInvalidatesWindow::NPP_SetWindow(NPP instance, NPWindow* window) +NPError NPNInvalidateRectInvalidatesWindow::NPP_SetWindow(NPP instance, NPWindow* npWindow) { - HWND newWindow = reinterpret_cast<HWND>(window->window); - if (newWindow == m_window) - return NPERR_NO_ERROR; - - if (m_window) { - ::RemovePropW(m_window, instancePointerProperty); - ::SetWindowLongPtr(m_window, GWLP_WNDPROC, reinterpret_cast<LONG_PTR>(m_originalWndProc)); - m_originalWndProc = 0; - } + NPError error = WindowedPluginTest::NPP_SetWindow(instance, npWindow); + if (error != NPERR_NO_ERROR) + return error; - m_window = newWindow; - if (!m_window) + if (!window()) return NPERR_NO_ERROR; - m_originalWndProc = reinterpret_cast<WNDPROC>(::SetWindowLongPtrW(m_window, GWLP_WNDPROC, reinterpret_cast<LONG_PTR>(wndProc))); - ::SetPropW(m_window, instancePointerProperty, this); - // The test harness's window (the one that contains the WebView) is off-screen and hidden. // We need to move it on-screen and make it visible in order for the plugin's window to // accumulate an update region when the DWM is disabled. - HWND testHarnessWindow = ::GetAncestor(m_window, GA_ROOT); + HWND testHarnessWindow = ::GetAncestor(window(), GA_ROOT); if (!testHarnessWindow) { pluginLog(instance, "Failed to get test harness window"); return NPERR_GENERIC_ERROR; @@ -141,14 +127,13 @@ NPError NPNInvalidateRectInvalidatesWindow::NPP_SetWindow(NPP instance, NPWindow return NPERR_NO_ERROR; } -LRESULT NPNInvalidateRectInvalidatesWindow::wndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) +LRESULT NPNInvalidateRectInvalidatesWindow::wndProc(UINT message, WPARAM wParam, LPARAM lParam, bool& handled) { - NPNInvalidateRectInvalidatesWindow* instance = reinterpret_cast<NPNInvalidateRectInvalidatesWindow*>(::GetPropW(hwnd, instancePointerProperty)); - if (message == WM_PAINT) - instance->onPaint(); + onPaint(); - return ::CallWindowProcW(instance->m_originalWndProc, hwnd, message, wParam, lParam); + handled = false; + return 0; } void NPNInvalidateRectInvalidatesWindow::onPaint() @@ -162,7 +147,7 @@ void NPNInvalidateRectInvalidatesWindow::onPaint() void NPNInvalidateRectInvalidatesWindow::testInvalidateRect() { RECT clientRect; - if (!::GetClientRect(m_window, &clientRect)) { + if (!::GetClientRect(window(), &clientRect)) { pluginLog(m_npp, "::GetClientRect failed"); return; } @@ -173,7 +158,7 @@ void NPNInvalidateRectInvalidatesWindow::testInvalidateRect() } // Clear the invalid region. - if (!::ValidateRect(m_window, 0)) { + if (!::ValidateRect(window(), 0)) { pluginLog(m_npp, "::ValidateRect failed"); return; } @@ -187,7 +172,7 @@ void NPNInvalidateRectInvalidatesWindow::testInvalidateRect() NPN_InvalidateRect(&rectToInvalidate); RECT invalidRect; - if (!::GetUpdateRect(m_window, &invalidRect, FALSE)) { + if (!::GetUpdateRect(window(), &invalidRect, FALSE)) { pluginLog(m_npp, "::GetUpdateRect failed"); return; } diff --git a/WebKitTools/DumpRenderTree/TestNetscapePlugIn/Tests/win/WindowRegionIsSetToClipRect.cpp b/WebKitTools/DumpRenderTree/TestNetscapePlugIn/Tests/win/WindowRegionIsSetToClipRect.cpp new file mode 100644 index 0000000..975a598 --- /dev/null +++ b/WebKitTools/DumpRenderTree/TestNetscapePlugIn/Tests/win/WindowRegionIsSetToClipRect.cpp @@ -0,0 +1,114 @@ +/* + * 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" + +#include "PluginObject.h" + +using namespace std; + +// The plugin's window's window region should be set to the plugin's clip rect. + +class WindowRegionIsSetToClipRect : public PluginTest { +public: + WindowRegionIsSetToClipRect(NPP, const string& identifier); + +private: + virtual NPError NPP_SetWindow(NPP, NPWindow*); + + bool m_didReceiveInitialSetWindowCall; +}; + +static PluginTest::Register<WindowRegionIsSetToClipRect> registrar("window-region-is-set-to-clip-rect"); + +WindowRegionIsSetToClipRect::WindowRegionIsSetToClipRect(NPP npp, const string& identifier) + : PluginTest(npp, identifier) + , m_didReceiveInitialSetWindowCall(false) +{ +} + +NPError WindowRegionIsSetToClipRect::NPP_SetWindow(NPP instance, NPWindow* window) +{ + if (m_didReceiveInitialSetWindowCall) + return NPERR_NO_ERROR; + m_didReceiveInitialSetWindowCall = true; + + if (window->type != NPWindowTypeWindow) { + pluginLog(instance, "window->type should be NPWindowTypeWindow but was %d", window->type); + return NPERR_GENERIC_ERROR; + } + + HWND hwnd = reinterpret_cast<HWND>(window->window); + + RECT regionRect; + if (::GetWindowRgnBox(hwnd, ®ionRect) == ERROR) { + pluginLog(instance, "::GetWindowRgnBox failed with error %u", ::GetLastError()); + return NPERR_GENERIC_ERROR; + } + + // This expected rect is based on the layout of window-region-is-set-to-clip-rect.html. + RECT expectedRect = { 50, 50, 100, 100 }; + if (!::EqualRect(®ionRect, &expectedRect)) { + pluginLog(instance, "Expected region rect {left=%u, top=%u, right=%u, bottom=%u}, but got {left=%d, top=%d, right=%d, bottom=%d}", expectedRect.left, expectedRect.top, expectedRect.right, expectedRect.bottom, regionRect.left, regionRect.top, regionRect.right, regionRect.bottom); + return NPERR_GENERIC_ERROR; + } + + pluginLog(instance, "PASS: Plugin's window's window region has been set as expected"); + + // While we're here, check that our window class doesn't have the CS_PARENTDC style, which + // defeats clipping by ignoring the window region and always clipping to the parent window. + // FIXME: It would be nice to have a pixel test that shows that we're + // getting clipped correctly, but unfortunately window regions are ignored + // during WM_PRINT (see <http://webkit.org/b/49034>). + wchar_t className[512]; + if (!::GetClassNameW(hwnd, className, _countof(className))) { + pluginLog(instance, "::GetClassName failed with error %u", ::GetLastError()); + return NPERR_GENERIC_ERROR; + } + +#ifdef DEBUG_ALL + const wchar_t webKitDLLName[] = L"WebKit_debug.dll"; +#else + const wchar_t webKitDLLName[] = L"WebKit.dll"; +#endif + HMODULE webKitModule = ::GetModuleHandleW(webKitDLLName); + if (!webKitModule) { + pluginLog(instance, "::GetModuleHandleW failed with error %u", ::GetLastError()); + return NPERR_GENERIC_ERROR; + } + + WNDCLASSW wndClass; + if (!::GetClassInfoW(webKitModule, className, &wndClass)) { + pluginLog(instance, "::GetClassInfoW failed with error %u", ::GetLastError()); + return NPERR_GENERIC_ERROR; + } + + if (wndClass.style & CS_PARENTDC) + pluginLog(instance, "FAIL: Plugin's window's class has the CS_PARENTDC style, which will defeat clipping"); + else + pluginLog(instance, "PASS: Plugin's window's class does not have the CS_PARENTDC style"); + + return NPERR_NO_ERROR; +} diff --git a/WebKitTools/DumpRenderTree/TestNetscapePlugIn/main.cpp b/WebKitTools/DumpRenderTree/TestNetscapePlugIn/main.cpp index e5246c4..2110a8a 100644 --- a/WebKitTools/DumpRenderTree/TestNetscapePlugIn/main.cpp +++ b/WebKitTools/DumpRenderTree/TestNetscapePlugIn/main.cpp @@ -29,6 +29,10 @@ #include <cstdlib> #include <string> +#ifdef XP_UNIX +#include <X11/Xlib.h> +#endif + #if !defined(NP_NO_CARBON) && defined(QD_HEADERS_ARE_PRIVATE) && QD_HEADERS_ARE_PRIVATE extern "C" void GlobalToLocal(Point*); #endif @@ -565,6 +569,54 @@ static int16_t handleEventCocoa(NPP instance, PluginObject* obj, NPCocoaEvent* e #endif // XP_MACOSX +#ifdef XP_UNIX +static int16_t handleEventX11(NPP instance, PluginObject* obj, XEvent* event) +{ + XButtonPressedEvent* buttonPressEvent = reinterpret_cast<XButtonPressedEvent*>(event); + XButtonReleasedEvent* buttonReleaseEvent = reinterpret_cast<XButtonReleasedEvent*>(event); + switch (event->type) { + case ButtonPress: + pluginLog(instance, "mouseDown at (%d, %d)", buttonPressEvent->x, buttonPressEvent->y); + if (obj->evaluateScriptOnMouseDownOrKeyDown && obj->mouseDownForEvaluateScript) + executeScript(obj, obj->evaluateScriptOnMouseDownOrKeyDown); + break; + case ButtonRelease: + pluginLog(instance, "mouseUp at (%d, %d)", buttonReleaseEvent->x, buttonReleaseEvent->y); + break; + case KeyPress: + // FIXME: extract key code + pluginLog(instance, "NOTIMPLEMENTED: keyDown '%c'", ' '); + if (obj->evaluateScriptOnMouseDownOrKeyDown && !obj->mouseDownForEvaluateScript) + executeScript(obj, obj->evaluateScriptOnMouseDownOrKeyDown); + break; + case KeyRelease: + // FIXME: extract key code + pluginLog(instance, "NOTIMPLEMENTED: keyUp '%c'", ' '); + break; + case GraphicsExpose: + pluginLog(instance, "updateEvt"); + break; + // NPAPI events + case FocusIn: + pluginLog(instance, "getFocusEvent"); + break; + case FocusOut: + pluginLog(instance, "loseFocusEvent"); + break; + case EnterNotify: + case LeaveNotify: + case MotionNotify: + pluginLog(instance, "adjustCursorEvent"); + break; + default: + pluginLog(instance, "event %d", event->type); + } + + fflush(stdout); + return 0; +} +#endif // XP_UNIX + int16_t NPP_HandleEvent(NPP instance, void *event) { PluginObject* obj = static_cast<PluginObject*>(instance->pdata); @@ -579,6 +631,8 @@ int16_t NPP_HandleEvent(NPP instance, void *event) assert(obj->eventModel == NPEventModelCocoa); return handleEventCocoa(instance, obj, static_cast<NPCocoaEvent*>(event)); +#elif defined(XP_UNIX) + return handleEventX11(instance, obj, static_cast<XEvent*>(event)); #else // FIXME: Implement for other platforms. return 0; diff --git a/WebKitTools/DumpRenderTree/TestNetscapePlugIn/win/TestNetscapePlugin.vcproj b/WebKitTools/DumpRenderTree/TestNetscapePlugIn/win/TestNetscapePlugin.vcproj index 74042bc..a2e6809 100644 --- a/WebKitTools/DumpRenderTree/TestNetscapePlugIn/win/TestNetscapePlugin.vcproj +++ b/WebKitTools/DumpRenderTree/TestNetscapePlugIn/win/TestNetscapePlugin.vcproj @@ -39,7 +39,7 @@ />
<Tool
Name="VCCLCompilerTool"
- AdditionalIncludeDirectories=""$(WebKitOutputDir)\Include";"$(WebKitOutputDir)\Include\JavaScriptCore";"$(WebKitOutputDir)\Include\WebCore\ForwardingHeaders";"$(ProjectDir)..\..\TestNetscapePlugin";"$(WebKitLibrariesDir)\include""
+ AdditionalIncludeDirectories=""$(ProjectDir)";"$(ProjectDir)..";"$(WebKitOutputDir)\Include";"$(WebKitOutputDir)\Include\JavaScriptCore";"$(WebKitOutputDir)\Include\WebCore\ForwardingHeaders";"$(WebKitLibrariesDir)\include""
PreprocessorDefinitions="_USRDLL;TESTNETSCAPEPLUGIN_EXPORTS;snprintf=_snprintf"
DisableSpecificWarnings="4819"
/>
@@ -55,6 +55,7 @@ />
<Tool
Name="VCLinkerTool"
+ AdditionalDependencies="Msimg32.lib"
OutputFile="$(OutDir)\$(ProjectName)$(WebKitConfigSuffix)\np$(ProjectName)$(WebKitConfigSuffix).dll"
ModuleDefinitionFile="TestNetscapePlugin$(WebKitConfigSuffix).def"
/>
@@ -109,7 +110,7 @@ />
<Tool
Name="VCCLCompilerTool"
- AdditionalIncludeDirectories=""$(WebKitOutputDir)\Include";"$(WebKitOutputDir)\Include\JavaScriptCore";"$(WebKitOutputDir)\Include\WebCore\ForwardingHeaders";"$(ProjectDir)..\..\TestNetscapePlugin";"$(WebKitLibrariesDir)\include""
+ AdditionalIncludeDirectories=""$(ProjectDir)";"$(ProjectDir)..";"$(WebKitOutputDir)\Include";"$(WebKitOutputDir)\Include\JavaScriptCore";"$(WebKitOutputDir)\Include\WebCore\ForwardingHeaders";"$(WebKitLibrariesDir)\include""
PreprocessorDefinitions="_USRDLL;TESTNETSCAPEPLUGIN_EXPORTS;snprintf=_snprintf"
DisableSpecificWarnings="4819"
/>
@@ -125,6 +126,7 @@ />
<Tool
Name="VCLinkerTool"
+ AdditionalDependencies="Msimg32.lib"
OutputFile="$(OutDir)\$(ProjectName)$(WebKitConfigSuffix)\np$(ProjectName)$(WebKitConfigSuffix).dll"
ModuleDefinitionFile="TestNetscapePlugin$(WebKitConfigSuffix).def"
/>
@@ -178,7 +180,7 @@ />
<Tool
Name="VCCLCompilerTool"
- AdditionalIncludeDirectories=""$(WebKitOutputDir)\Include";"$(WebKitOutputDir)\Include\JavaScriptCore";"$(WebKitOutputDir)\Include\WebCore\ForwardingHeaders";"$(ProjectDir)..\..\TestNetscapePlugin";"$(WebKitLibrariesDir)\include""
+ AdditionalIncludeDirectories=""$(ProjectDir)";"$(ProjectDir)..";"$(WebKitOutputDir)\Include";"$(WebKitOutputDir)\Include\JavaScriptCore";"$(WebKitOutputDir)\Include\WebCore\ForwardingHeaders";"$(WebKitLibrariesDir)\include""
PreprocessorDefinitions="_USRDLL;TESTNETSCAPEPLUGIN_EXPORTS;snprintf=_snprintf"
RuntimeLibrary="3"
DisableSpecificWarnings="4819"
@@ -195,6 +197,7 @@ />
<Tool
Name="VCLinkerTool"
+ AdditionalDependencies="Msimg32.lib"
OutputFile="$(OutDir)\$(ProjectName)$(WebKitConfigSuffix)\np$(ProjectName)$(WebKitConfigSuffix).dll"
ModuleDefinitionFile="TestNetscapePlugin$(WebKitConfigSuffix).def"
/>
@@ -248,7 +251,7 @@ />
<Tool
Name="VCCLCompilerTool"
- AdditionalIncludeDirectories=""$(WebKitOutputDir)\Include";"$(WebKitOutputDir)\Include\JavaScriptCore";"$(WebKitOutputDir)\Include\WebCore\ForwardingHeaders";"$(ProjectDir)..\..\TestNetscapePlugin";"$(WebKitLibrariesDir)\include""
+ AdditionalIncludeDirectories=""$(ProjectDir)";"$(ProjectDir)..";"$(WebKitOutputDir)\Include";"$(WebKitOutputDir)\Include\JavaScriptCore";"$(WebKitOutputDir)\Include\WebCore\ForwardingHeaders";"$(WebKitLibrariesDir)\include""
PreprocessorDefinitions="_USRDLL;TESTNETSCAPEPLUGIN_EXPORTS;snprintf=_snprintf"
DisableSpecificWarnings="4819"
/>
@@ -264,6 +267,7 @@ />
<Tool
Name="VCLinkerTool"
+ AdditionalDependencies="Msimg32.lib"
OutputFile="$(OutDir)\$(ProjectName)$(WebKitConfigSuffix)\np$(ProjectName)$(WebKitConfigSuffix).dll"
ModuleDefinitionFile="TestNetscapePlugin$(WebKitConfigSuffix).def"
/>
@@ -317,7 +321,7 @@ />
<Tool
Name="VCCLCompilerTool"
- AdditionalIncludeDirectories=""$(WebKitOutputDir)\Include";"$(WebKitOutputDir)\Include\JavaScriptCore";"$(WebKitOutputDir)\Include\WebCore\ForwardingHeaders";"$(ProjectDir)..\..\TestNetscapePlugin";"$(WebKitLibrariesDir)\include""
+ AdditionalIncludeDirectories=""$(ProjectDir)";"$(ProjectDir)..";"$(WebKitOutputDir)\Include";"$(WebKitOutputDir)\Include\JavaScriptCore";"$(WebKitOutputDir)\Include\WebCore\ForwardingHeaders";"$(WebKitLibrariesDir)\include""
PreprocessorDefinitions="_USRDLL;TESTNETSCAPEPLUGIN_EXPORTS;snprintf=_snprintf"
RuntimeLibrary="3"
DisableSpecificWarnings="4819"
@@ -334,6 +338,7 @@ />
<Tool
Name="VCLinkerTool"
+ AdditionalDependencies="Msimg32.lib"
OutputFile="$(OutDir)\$(ProjectName)$(WebKitConfigSuffix)\np$(ProjectName)$(WebKitConfigSuffix).dll"
ModuleDefinitionFile="TestNetscapePlugin$(WebKitConfigSuffix).def"
/>
@@ -375,6 +380,10 @@ >
</File>
<File
+ RelativePath="..\Tests\EvaluateJSAfterRemovingPluginElement.cpp"
+ >
+ </File>
+ <File
RelativePath="..\Tests\NPRuntimeObjectFromDestroyedPlugin.cpp"
>
</File>
@@ -398,6 +407,10 @@ Name="win"
>
<File
+ RelativePath="..\Tests\win\DrawsGradient.cpp"
+ >
+ </File>
+ <File
RelativePath="..\Tests\win\GetValueNetscapeWindow.cpp"
>
</File>
@@ -409,8 +422,24 @@ RelativePath="..\Tests\win\WindowGeometryInitializedBeforeSetWindow.cpp"
>
</File>
+ <File
+ RelativePath="..\Tests\win\WindowRegionIsSetToClipRect.cpp"
+ >
+ </File>
</Filter>
</Filter>
+ <Filter
+ Name="win"
+ >
+ <File
+ RelativePath=".\WindowedPluginTest.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\WindowedPluginTest.h"
+ >
+ </File>
+ </Filter>
<File
RelativePath="..\main.cpp"
>
diff --git a/WebKitTools/DumpRenderTree/TestNetscapePlugIn/win/WindowedPluginTest.cpp b/WebKitTools/DumpRenderTree/TestNetscapePlugIn/win/WindowedPluginTest.cpp new file mode 100644 index 0000000..96b51f8 --- /dev/null +++ b/WebKitTools/DumpRenderTree/TestNetscapePlugIn/win/WindowedPluginTest.cpp @@ -0,0 +1,71 @@ +/* + * 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 "WindowedPluginTest.h" + +using namespace std; + +static const wchar_t instancePointerProperty[] = L"org.webkit.TestNetscapePlugin.WindowedPluginTest.InstancePointer"; + +WindowedPluginTest::WindowedPluginTest(NPP npp, const string& identifier) + : PluginTest(npp, identifier) + , m_window(0) + , m_originalWndProc(0) +{ +} + +NPError WindowedPluginTest::NPP_SetWindow(NPP instance, NPWindow* window) +{ + HWND newWindow = reinterpret_cast<HWND>(window->window); + if (newWindow == m_window) + return NPERR_NO_ERROR; + + if (m_window) { + ::RemovePropW(m_window, instancePointerProperty); + ::SetWindowLongPtr(m_window, GWLP_WNDPROC, reinterpret_cast<LONG_PTR>(m_originalWndProc)); + m_originalWndProc = 0; + } + + m_window = newWindow; + if (!m_window) + return NPERR_NO_ERROR; + + m_originalWndProc = reinterpret_cast<WNDPROC>(::SetWindowLongPtrW(m_window, GWLP_WNDPROC, reinterpret_cast<LONG_PTR>(staticWndProc))); + ::SetPropW(m_window, instancePointerProperty, this); + + return NPERR_NO_ERROR; +} + +LRESULT WindowedPluginTest::staticWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) +{ + WindowedPluginTest* instance = reinterpret_cast<WindowedPluginTest*>(::GetPropW(hwnd, instancePointerProperty)); + + bool handled = false; + LRESULT result = instance->wndProc(message, wParam, lParam, handled); + if (handled) + return result; + + return ::CallWindowProcW(instance->m_originalWndProc, hwnd, message, wParam, lParam); +} diff --git a/WebKitTools/DumpRenderTree/TestNetscapePlugIn/win/WindowedPluginTest.h b/WebKitTools/DumpRenderTree/TestNetscapePlugIn/win/WindowedPluginTest.h new file mode 100644 index 0000000..7abc734 --- /dev/null +++ b/WebKitTools/DumpRenderTree/TestNetscapePlugIn/win/WindowedPluginTest.h @@ -0,0 +1,50 @@ +/* + * 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. + */ + +#ifndef WindowedPluginTest_h +#define WindowedPluginTest_h + +#include "PluginTest.h" + +class WindowedPluginTest : public PluginTest { +protected: + WindowedPluginTest(NPP, const std::string& identifier); + + HWND window() const { return m_window; } + + // For derived classes to override + virtual LRESULT wndProc(UINT message, WPARAM, LPARAM, bool& handled) = 0; + + // PluginTest + virtual NPError NPP_SetWindow(NPP, NPWindow*); + +private: + static LRESULT CALLBACK staticWndProc(HWND, UINT message, WPARAM, LPARAM); + + HWND m_window; + WNDPROC m_originalWndProc; +}; + +#endif // WindowedPluginTest_h diff --git a/WebKitTools/DumpRenderTree/chromium/EventSender.cpp b/WebKitTools/DumpRenderTree/chromium/EventSender.cpp index e250dfc..ec16cf7 100644 --- a/WebKitTools/DumpRenderTree/chromium/EventSender.cpp +++ b/WebKitTools/DumpRenderTree/chromium/EventSender.cpp @@ -873,6 +873,7 @@ void EventSender::sendCurrentTouchEvent(const WebInputEvent::Type type) WebTouchEvent touchEvent; touchEvent.type = type; touchEvent.modifiers = touchModifiers; + touchEvent.timeStampSeconds = getCurrentEventTimeSec(); touchEvent.touchPointsLength = touchPoints.size(); for (unsigned i = 0; i < touchPoints.size(); ++i) touchEvent.touchPoints[i] = touchPoints[i]; diff --git a/WebKitTools/DumpRenderTree/chromium/LayoutTestController.cpp b/WebKitTools/DumpRenderTree/chromium/LayoutTestController.cpp index d713b04..5b0c844 100644 --- a/WebKitTools/DumpRenderTree/chromium/LayoutTestController.cpp +++ b/WebKitTools/DumpRenderTree/chromium/LayoutTestController.cpp @@ -71,6 +71,8 @@ using namespace std; LayoutTestController::LayoutTestController(TestShell* shell) : m_shell(shell) + , m_closeRemainingWindows(false) + , m_deferMainResourceDataLoad(false) , m_workQueue(this) { @@ -1486,6 +1488,9 @@ void LayoutTestController::setEditingBehavior(const CppArgumentList& arguments, } else if (key == "win") { m_shell->preferences()->editingBehavior = WebSettings::EditingBehaviorWin; m_shell->applyPreferences(); + } else if (key == "unix") { + m_shell->preferences()->editingBehavior = WebSettings::EditingBehaviorUnix; + m_shell->applyPreferences(); } else logErrorToConsole("Passed invalid editing behavior. Should be 'mac' or 'win'."); } diff --git a/WebKitTools/DumpRenderTree/chromium/TestShell.h b/WebKitTools/DumpRenderTree/chromium/TestShell.h index ca06812..06e77cc 100644 --- a/WebKitTools/DumpRenderTree/chromium/TestShell.h +++ b/WebKitTools/DumpRenderTree/chromium/TestShell.h @@ -144,7 +144,7 @@ public: // The JavaScript flags are specified as a vector of strings. Each element of the vector is full flags string // which can contain multiple flags (e.g. "--xxx --yyy"). With multiple load testing it is possible to specify // separate sets of flags to each load. - std::string javaScriptFlagsForLoad(size_t load) { return (load >= 0 && load < m_javaScriptFlags.size()) ? m_javaScriptFlags[load] : ""; } + std::string javaScriptFlagsForLoad(size_t load) { return (load < m_javaScriptFlags.size()) ? m_javaScriptFlags[load] : ""; } void setJavaScriptFlags(Vector<std::string> javaScriptFlags) { m_javaScriptFlags = javaScriptFlags; } // Set whether to dump when the loaded page has finished processing. This is used with multiple load diff --git a/WebKitTools/DumpRenderTree/chromium/WebViewHost.cpp b/WebKitTools/DumpRenderTree/chromium/WebViewHost.cpp index 847e7dc..2f9bdfb 100644 --- a/WebKitTools/DumpRenderTree/chromium/WebViewHost.cpp +++ b/WebKitTools/DumpRenderTree/chromium/WebViewHost.cpp @@ -940,11 +940,16 @@ void WebViewHost::didChangeLocationWithinPage(WebFrame* frame) void WebViewHost::assignIdentifierToRequest(WebFrame*, unsigned identifier, const WebURLRequest& request) { - if (!m_shell->shouldDumpResourceLoadCallbacks()) - return; + ASSERT(!m_resourceIdentifierMap.contains(identifier)); m_resourceIdentifierMap.set(identifier, descriptionSuitableForTestResult(request.url().spec())); } +void WebViewHost::removeIdentifierForRequest(unsigned identifier) +{ + ASSERT(m_resourceIdentifierMap.contains(identifier)); + m_resourceIdentifierMap.remove(identifier); +} + void WebViewHost::willSendRequest(WebFrame*, unsigned identifier, WebURLRequest& request, const WebURLResponse& redirectResponse) { // Need to use GURL for host() and SchemeIs() @@ -1022,7 +1027,7 @@ void WebViewHost::didFinishResourceLoad(WebFrame*, unsigned identifier) printResourceDescription(identifier); fputs(" - didFinishLoading\n", stdout); } - m_resourceIdentifierMap.remove(identifier); + removeIdentifierForRequest(identifier); } void WebViewHost::didFailResourceLoad(WebFrame*, unsigned identifier, const WebURLError& error) @@ -1033,7 +1038,7 @@ void WebViewHost::didFailResourceLoad(WebFrame*, unsigned identifier, const WebU fputs(webkit_support::MakeURLErrorDescription(error).c_str(), stdout); fputs("\n", stdout); } - m_resourceIdentifierMap.remove(identifier); + removeIdentifierForRequest(identifier); } void WebViewHost::didDisplayInsecureContent(WebFrame*) diff --git a/WebKitTools/DumpRenderTree/chromium/WebViewHost.h b/WebKitTools/DumpRenderTree/chromium/WebViewHost.h index 1380ebd..f21e663 100644 --- a/WebKitTools/DumpRenderTree/chromium/WebViewHost.h +++ b/WebKitTools/DumpRenderTree/chromium/WebViewHost.h @@ -185,6 +185,7 @@ class WebViewHost : public WebKit::WebViewClient, public WebKit::WebFrameClient, virtual void didNavigateWithinPage(WebKit::WebFrame*, bool isNewNavigation); virtual void didChangeLocationWithinPage(WebKit::WebFrame*); virtual void assignIdentifierToRequest(WebKit::WebFrame*, unsigned identifier, const WebKit::WebURLRequest&); + virtual void removeIdentifierForRequest(unsigned identifier); virtual void willSendRequest(WebKit::WebFrame*, unsigned identifier, WebKit::WebURLRequest&, const WebKit::WebURLResponse&); virtual void didReceiveResponse(WebKit::WebFrame*, unsigned identifier, const WebKit::WebURLResponse&); virtual void didFinishResourceLoad(WebKit::WebFrame*, unsigned identifier); diff --git a/WebKitTools/DumpRenderTree/gtk/DumpRenderTree.cpp b/WebKitTools/DumpRenderTree/gtk/DumpRenderTree.cpp index 1c851d7..54acc49 100644 --- a/WebKitTools/DumpRenderTree/gtk/DumpRenderTree.cpp +++ b/WebKitTools/DumpRenderTree/gtk/DumpRenderTree.cpp @@ -137,10 +137,9 @@ static void initializeGtkFontSettings(const char* testURL) GtkSettings* settings = gtk_settings_get_default(); if (!settings) return; - g_object_set(settings, "gtk-xft-antialias", 1, NULL); - g_object_set(settings, "gtk-xft-hinting", 1, NULL); - g_object_set(settings, "gtk-xft-hintstyle", "hintfull", NULL); - g_object_set(settings, "gtk-font-name", "Liberation Sans 16", NULL); + g_object_set(settings, "gtk-xft-antialias", 1, + "gtk-xft-hinting", 0, + "gtk-font-name", "Liberation Sans 16", NULL); // One test needs subpixel anti-aliasing turned on, but generally we // want all text in other tests to use to grayscale anti-aliasing. diff --git a/WebKitTools/DumpRenderTree/gtk/LayoutTestControllerGtk.cpp b/WebKitTools/DumpRenderTree/gtk/LayoutTestControllerGtk.cpp index 688b3f8..ab70a3e 100644 --- a/WebKitTools/DumpRenderTree/gtk/LayoutTestControllerGtk.cpp +++ b/WebKitTools/DumpRenderTree/gtk/LayoutTestControllerGtk.cpp @@ -813,8 +813,10 @@ void LayoutTestController::setEditingBehavior(const char* editingBehavior) if (!strcmp(editingBehavior, "win")) g_object_set(G_OBJECT(settings), "editing-behavior", WEBKIT_EDITING_BEHAVIOR_WINDOWS, NULL); - if (!strcmp(editingBehavior, "mac")) + else if (!strcmp(editingBehavior, "mac")) g_object_set(G_OBJECT(settings), "editing-behavior", WEBKIT_EDITING_BEHAVIOR_MAC, NULL); + else if (!strcmp(editingBehavior, "unix")) + g_object_set(G_OBJECT(settings), "editing-behavior", WEBKIT_EDITING_BEHAVIOR_UNIX, NULL); } void LayoutTestController::abortModal() diff --git a/WebKitTools/DumpRenderTree/gtk/fonts/fonts.conf b/WebKitTools/DumpRenderTree/gtk/fonts/fonts.conf index 6eb057e..2d9af17 100644 --- a/WebKitTools/DumpRenderTree/gtk/fonts/fonts.conf +++ b/WebKitTools/DumpRenderTree/gtk/fonts/fonts.conf @@ -2,6 +2,19 @@ <!DOCTYPE fontconfig SYSTEM "fonts.dtd"> <fontconfig> + <!-- Due to patent (http://freetype.sourceforge.net/patents.html) + issues hinting gives different results depending on the + freetype version of the linux distribution, avoiding hinting + gives more consistent results. When all the distributions + release freetype the 2.4, which enables by default the + hinting method that was patented, we could undo this change + and try the hinting again. --> + <match target="font"> + <edit name="hinting" mode="assign"> + <bool>false</bool> + </edit> + </match> + <!-- The sans-serif font should be Liberation Serif --> <match target="pattern"> <test qual="any" name="family"> @@ -158,6 +171,9 @@ <edit name="family" mode="assign"> <string>Liberation Serif</string> </edit> + <edit name="hinting" mode="assign"> + <bool>true</bool> + </edit> <edit name="hintstyle" mode="assign"> <const>hintslight</const> </edit> @@ -175,7 +191,7 @@ <edit name="hintstyle" mode="assign"> <const>hintfull</const> </edit> - <edit name="hinting" mode="assign"> + <edit name="hinting" mode="assign"> <bool>false</bool> </edit> </match> @@ -187,6 +203,9 @@ <edit name="family" mode="assign"> <string>Liberation Serif</string> </edit> + <edit name="hinting" mode="assign"> + <bool>true</bool> + </edit> <edit name="autohint" mode="assign"> <bool>true</bool> </edit> @@ -202,6 +221,9 @@ <edit name="family" mode="assign"> <string>Liberation Serif</string> </edit> + <edit name="hinting" mode="assign"> + <bool>true</bool> + </edit> <edit name="autohint" mode="assign"> <bool>false</bool> </edit> @@ -217,6 +239,9 @@ <edit name="family" mode="assign"> <string>Liberation Serif</string> </edit> + <edit name="hinting" mode="assign"> + <bool>true</bool> + </edit> <edit name="autohint" mode="assign"> <bool>true</bool> </edit> diff --git a/WebKitTools/DumpRenderTree/mac/LayoutTestControllerMac.mm b/WebKitTools/DumpRenderTree/mac/LayoutTestControllerMac.mm index 150b6f9..431d4e9 100644 --- a/WebKitTools/DumpRenderTree/mac/LayoutTestControllerMac.mm +++ b/WebKitTools/DumpRenderTree/mac/LayoutTestControllerMac.mm @@ -935,8 +935,10 @@ void LayoutTestController::setEditingBehavior(const char* editingBehavior) NSString* editingBehaviorNS = [[NSString alloc] initWithUTF8String:editingBehavior]; if ([editingBehaviorNS isEqualToString:@"mac"]) [[WebPreferences standardPreferences] setEditingBehavior:WebKitEditingMacBehavior]; - if ([editingBehaviorNS isEqualToString:@"win"]) + else if ([editingBehaviorNS isEqualToString:@"win"]) [[WebPreferences standardPreferences] setEditingBehavior:WebKitEditingWinBehavior]; + else if ([editingBehaviorNS isEqualToString:@"unix"]) + [[WebPreferences standardPreferences] setEditingBehavior:WebKitEditingUnixBehavior]; [editingBehaviorNS release]; } diff --git a/WebKitTools/DumpRenderTree/qt/LayoutTestControllerQt.cpp b/WebKitTools/DumpRenderTree/qt/LayoutTestControllerQt.cpp index f99ec4f..3e50e06 100644 --- a/WebKitTools/DumpRenderTree/qt/LayoutTestControllerQt.cpp +++ b/WebKitTools/DumpRenderTree/qt/LayoutTestControllerQt.cpp @@ -810,5 +810,10 @@ bool LayoutTestController::hasSpellingMarker(int, int) return false; } +QVariantList LayoutTestController::nodesFromRect(const QWebElement& document, int x, int y, unsigned top, unsigned right, unsigned bottom, unsigned left, bool ignoreClipping) +{ + return DumpRenderTreeSupportQt::nodesFromRect(document, x, y, top, right, bottom, left, ignoreClipping); +} + const unsigned LayoutTestController::maxViewWidth = 800; const unsigned LayoutTestController::maxViewHeight = 600; diff --git a/WebKitTools/DumpRenderTree/qt/LayoutTestControllerQt.h b/WebKitTools/DumpRenderTree/qt/LayoutTestControllerQt.h index 11d72e4..dfb12fe 100644 --- a/WebKitTools/DumpRenderTree/qt/LayoutTestControllerQt.h +++ b/WebKitTools/DumpRenderTree/qt/LayoutTestControllerQt.h @@ -222,6 +222,8 @@ public slots: void abortModal() {} bool hasSpellingMarker(int from, int length); + QVariantList nodesFromRect(const QWebElement& document, int x, int y, unsigned top, unsigned right, unsigned bottom, unsigned left, bool ignoreClipping); + /* Policy values: 'on', 'auto' or 'off'. Orientation values: 'vertical' or 'horizontal'. diff --git a/WebKitTools/DumpRenderTree/qt/TestNetscapePlugin/TestNetscapePlugin.pro b/WebKitTools/DumpRenderTree/qt/TestNetscapePlugin/TestNetscapePlugin.pro index b958025..1d460d7 100644 --- a/WebKitTools/DumpRenderTree/qt/TestNetscapePlugin/TestNetscapePlugin.pro +++ b/WebKitTools/DumpRenderTree/qt/TestNetscapePlugin/TestNetscapePlugin.pro @@ -29,6 +29,7 @@ SOURCES = PluginObject.cpp \ PluginTest.cpp \ TestObject.cpp \ Tests/DocumentOpenInDestroyStream.cpp \ + Tests/EvaluateJSAfterRemovingPluginElement.cpp \ Tests/NPRuntimeObjectFromDestroyedPlugin.cpp \ Tests/NPRuntimeRemoveProperty.cpp \ Tests/NullNPPGetValuePointer.cpp \ diff --git a/WebKitTools/DumpRenderTree/unix/TestNetscapePlugin/TestNetscapePlugin.cpp b/WebKitTools/DumpRenderTree/unix/TestNetscapePlugin/TestNetscapePlugin.cpp index 14bb8ef..2298ef1 100644 --- a/WebKitTools/DumpRenderTree/unix/TestNetscapePlugin/TestNetscapePlugin.cpp +++ b/WebKitTools/DumpRenderTree/unix/TestNetscapePlugin/TestNetscapePlugin.cpp @@ -372,7 +372,9 @@ webkit_test_plugin_set_value(NPP instance, NPNVariable variable, void* value) char * NP_GetMIMEDescription(void) { - return const_cast<char*>("application/x-webkit-test-netscape:testnetscape:test netscape content"); + // We sentence-case the mime-type here to ensure that ports are not + // case-sensitive when loading plugins. See https://webkit.org/b/36815 + return const_cast<char*>("application/x-Webkit-Test-Netscape:testnetscape:test netscape content"); } NPError diff --git a/WebKitTools/DumpRenderTree/win/DumpRenderTree.cpp b/WebKitTools/DumpRenderTree/win/DumpRenderTree.cpp index 5138562..7c3d9b3 100644 --- a/WebKitTools/DumpRenderTree/win/DumpRenderTree.cpp +++ b/WebKitTools/DumpRenderTree/win/DumpRenderTree.cpp @@ -98,7 +98,6 @@ PolicyDelegate* policyDelegate; COMPtr<FrameLoadDelegate> sharedFrameLoadDelegate; COMPtr<UIDelegate> sharedUIDelegate; COMPtr<EditingDelegate> sharedEditingDelegate; -COMPtr<ResourceLoadDelegate> sharedResourceLoadDelegate; COMPtr<HistoryDelegate> sharedHistoryDelegate; IWebFrame* frame; @@ -1201,7 +1200,10 @@ IWebView* createWebViewAndOffscreenWindow(HWND* webViewWindow) if (FAILED(viewEditing->setEditingDelegate(sharedEditingDelegate.get()))) return 0; - if (FAILED(webView->setResourceLoadDelegate(sharedResourceLoadDelegate.get()))) + ResourceLoadDelegate* resourceLoadDelegate = new ResourceLoadDelegate(); + HRESULT result = webView->setResourceLoadDelegate(resourceLoadDelegate); + resourceLoadDelegate->Release(); // The delegate is owned by the WebView, so release our reference to it. + if (FAILED(result)) return 0; openWindows().append(hostWindow); @@ -1285,7 +1287,6 @@ int main(int argc, char* argv[]) sharedFrameLoadDelegate.adoptRef(new FrameLoadDelegate); sharedUIDelegate.adoptRef(new UIDelegate); sharedEditingDelegate.adoptRef(new EditingDelegate); - sharedResourceLoadDelegate.adoptRef(new ResourceLoadDelegate); sharedHistoryDelegate.adoptRef(new HistoryDelegate); // FIXME - need to make DRT pass with Windows native controls <http://bugs.webkit.org/show_bug.cgi?id=25592> diff --git a/WebKitTools/DumpRenderTree/win/LayoutTestControllerWin.cpp b/WebKitTools/DumpRenderTree/win/LayoutTestControllerWin.cpp index d7c41e0..386f118 100644 --- a/WebKitTools/DumpRenderTree/win/LayoutTestControllerWin.cpp +++ b/WebKitTools/DumpRenderTree/win/LayoutTestControllerWin.cpp @@ -1383,8 +1383,10 @@ void LayoutTestController::setEditingBehavior(const char* editingBehavior) string behaviorString(editingBehavior); if (behaviorString == "mac") preferences->setEditingBehavior(WebKitEditingMacBehavior); - if (behaviorString == "win") + else if (behaviorString == "win") preferences->setEditingBehavior(WebKitEditingWinBehavior); + else if (behaviorString == "unix") + preferences->setEditingBehavior(WebKitEditingUnixBehavior); } void LayoutTestController::abortModal() diff --git a/WebKitTools/DumpRenderTree/win/PixelDumpSupportWin.cpp b/WebKitTools/DumpRenderTree/win/PixelDumpSupportWin.cpp index b0c76d6..752cc39 100644 --- a/WebKitTools/DumpRenderTree/win/PixelDumpSupportWin.cpp +++ b/WebKitTools/DumpRenderTree/win/PixelDumpSupportWin.cpp @@ -63,7 +63,7 @@ PassRefPtr<BitmapContext> createBitmapContextFromWebView(bool onscreen, bool inc HDC memoryDC = CreateCompatibleDC(0); SelectObject(memoryDC, bitmap); - SendMessage(webViewWindow, WM_PRINTCLIENT, reinterpret_cast<WPARAM>(memoryDC), PRF_CLIENT | PRF_CHILDREN | PRF_OWNED); + SendMessage(webViewWindow, WM_PRINT, reinterpret_cast<WPARAM>(memoryDC), PRF_CLIENT | PRF_CHILDREN | PRF_OWNED); DeleteDC(memoryDC); BITMAP info = {0}; @@ -73,7 +73,7 @@ PassRefPtr<BitmapContext> createBitmapContextFromWebView(bool onscreen, bool inc #if PLATFORM(CG) RetainPtr<CGColorSpaceRef> colorSpace(AdoptCF, CGColorSpaceCreateDeviceRGB()); CGContextRef context = CGBitmapContextCreate(info.bmBits, info.bmWidth, info.bmHeight, 8, - info.bmWidthBytes, colorSpace.get(), kCGBitmapByteOrder32Little | kCGImageAlphaPremultipliedFirst); + info.bmWidthBytes, colorSpace.get(), kCGBitmapByteOrder32Host | kCGImageAlphaPremultipliedFirst); #elif PLATFORM(CAIRO) cairo_surface_t* image = cairo_image_surface_create_for_data((unsigned char*)info.bmBits, CAIRO_FORMAT_ARGB32, info.bmWidth, info.bmHeight, info.bmWidthBytes); diff --git a/WebKitTools/DumpRenderTree/win/ResourceLoadDelegate.cpp b/WebKitTools/DumpRenderTree/win/ResourceLoadDelegate.cpp index 825366a..09b07d6 100644 --- a/WebKitTools/DumpRenderTree/win/ResourceLoadDelegate.cpp +++ b/WebKitTools/DumpRenderTree/win/ResourceLoadDelegate.cpp @@ -35,7 +35,6 @@ #include <comutil.h> #include <sstream> #include <tchar.h> -#include <wtf/HashMap.h> #include <wtf/Vector.h> using namespace std; @@ -60,26 +59,17 @@ static inline BSTR BSTRFromString(const string& str) return result; } -typedef HashMap<unsigned long, wstring> IdentifierMap; - -IdentifierMap& urlMap() -{ - static IdentifierMap urlMap; - - return urlMap; -} - -static wstring descriptionSuitableForTestResult(unsigned long identifier) +wstring ResourceLoadDelegate::descriptionSuitableForTestResult(unsigned long identifier) const { - IdentifierMap::iterator it = urlMap().find(identifier); + IdentifierMap::const_iterator it = m_urlMap.find(identifier); - if (it == urlMap().end()) + if (it == m_urlMap.end()) return L"<unknown>"; return urlSuitableForTestResult(it->second); } -static wstring descriptionSuitableForTestResult(IWebURLRequest* request) +wstring ResourceLoadDelegate::descriptionSuitableForTestResult(IWebURLRequest* request) { if (!request) return L"(null)"; @@ -108,7 +98,7 @@ static wstring descriptionSuitableForTestResult(IWebURLRequest* request) return L"<NSURLRequest URL " + url + L", main document URL " + mainDocumentURL + L", http method " + httpMethod + L">"; } -static wstring descriptionSuitableForTestResult(IWebURLResponse* response) +wstring ResourceLoadDelegate::descriptionSuitableForTestResult(IWebURLResponse* response) { if (!response) return L"(null)"; @@ -128,7 +118,7 @@ static wstring descriptionSuitableForTestResult(IWebURLResponse* response) return L"<NSURLResponse " + url + L", http status code " + wstringFromInt(statusCode) + L">"; } -static wstring descriptionSuitableForTestResult(IWebError* error, unsigned long identifier) +wstring ResourceLoadDelegate::descriptionSuitableForTestResult(IWebError* error, unsigned long identifier) const { wstring result = L"<NSError "; @@ -197,6 +187,8 @@ HRESULT STDMETHODCALLTYPE ResourceLoadDelegate::QueryInterface(REFIID riid, void *ppvObject = static_cast<IWebResourceLoadDelegate*>(this); else if (IsEqualGUID(riid, IID_IWebResourceLoadDelegate)) *ppvObject = static_cast<IWebResourceLoadDelegate*>(this); + else if (IsEqualGUID(riid, IID_IWebResourceLoadDelegatePrivate2)) + *ppvObject = static_cast<IWebResourceLoadDelegatePrivate2*>(this); else return E_NOINTERFACE; @@ -229,12 +221,22 @@ HRESULT STDMETHODCALLTYPE ResourceLoadDelegate::identifierForInitialRequest( if (FAILED(request->URL(&urlStr))) return E_FAIL; + ASSERT(!urlMap().contains(identifier)); urlMap().set(identifier, wstringFromBSTR(urlStr)); } return S_OK; } +HRESULT STDMETHODCALLTYPE ResourceLoadDelegate::removeIdentifierForRequest( + /* [in] */ IWebView* webView, + /* [in] */ unsigned long identifier) +{ + urlMap().remove(identifier); + + return S_OK; +} + HRESULT STDMETHODCALLTYPE ResourceLoadDelegate::willSendRequest( /* [in] */ IWebView* webView, /* [in] */ unsigned long identifier, @@ -351,11 +353,12 @@ HRESULT STDMETHODCALLTYPE ResourceLoadDelegate::didFinishLoadingFromDataSource( { if (!done && gLayoutTestController->dumpResourceLoadCallbacks()) { printf("%S - didFinishLoading\n", - descriptionSuitableForTestResult(identifier).c_str()), - urlMap().remove(identifier); + descriptionSuitableForTestResult(identifier).c_str()); } - return S_OK; + removeIdentifierForRequest(webView, identifier); + + return S_OK; } HRESULT STDMETHODCALLTYPE ResourceLoadDelegate::didFailLoadingWithError( @@ -368,8 +371,9 @@ HRESULT STDMETHODCALLTYPE ResourceLoadDelegate::didFailLoadingWithError( printf("%S - didFailLoadingWithError: %S\n", descriptionSuitableForTestResult(identifier).c_str(), descriptionSuitableForTestResult(error, identifier).c_str()); - urlMap().remove(identifier); } + removeIdentifierForRequest(webView, identifier); + return S_OK; } diff --git a/WebKitTools/DumpRenderTree/win/ResourceLoadDelegate.h b/WebKitTools/DumpRenderTree/win/ResourceLoadDelegate.h index 924727b..3f20f47 100644 --- a/WebKitTools/DumpRenderTree/win/ResourceLoadDelegate.h +++ b/WebKitTools/DumpRenderTree/win/ResourceLoadDelegate.h @@ -30,8 +30,10 @@ #define ResourceLoadDelegate_h #include <WebKit/WebKit.h> +#include <string> +#include <wtf/HashMap.h> -class ResourceLoadDelegate : public IWebResourceLoadDelegate { +class ResourceLoadDelegate : public IWebResourceLoadDelegate, public IWebResourceLoadDelegatePrivate2 { public: ResourceLoadDelegate(); virtual ~ResourceLoadDelegate(); @@ -95,8 +97,22 @@ public: /* [in] */ IWebView *webView, /* [in] */ IWebError *error, /* [in] */ IWebDataSource *dataSource) { return E_NOTIMPL; } + + // IWebResourceLoadDelegatePrivate2 + virtual HRESULT STDMETHODCALLTYPE removeIdentifierForRequest( + /* [in] */ IWebView *webView, + /* [in] */ unsigned long identifier); -protected: +private: + static std::wstring descriptionSuitableForTestResult(IWebURLRequest*); + static std::wstring descriptionSuitableForTestResult(IWebURLResponse*); + std::wstring descriptionSuitableForTestResult(unsigned long) const; + std::wstring descriptionSuitableForTestResult(IWebError*, unsigned long) const; + + typedef HashMap<unsigned long, std::wstring> IdentifierMap; + IdentifierMap& urlMap() { return m_urlMap; } + IdentifierMap m_urlMap; + ULONG m_refCount; }; diff --git a/WebKitTools/GNUmakefile.am b/WebKitTools/GNUmakefile.am index 2700869..d20b3b5 100644 --- a/WebKitTools/GNUmakefile.am +++ b/WebKitTools/GNUmakefile.am @@ -167,6 +167,7 @@ TestNetscapePlugin_libtestnetscapeplugin_la_SOURCES = \ WebKitTools/DumpRenderTree/unix/TestNetscapePlugin/ForwardingHeaders/WebKit/npruntime.h \ WebKitTools/DumpRenderTree/unix/TestNetscapePlugin/TestNetscapePlugin.cpp \ WebKitTools/DumpRenderTree/TestNetscapePlugIn/Tests/DocumentOpenInDestroyStream.cpp \ + WebKitTools/DumpRenderTree/TestNetscapePlugIn/Tests/EvaluateJSAfterRemovingPluginElement.cpp \ WebKitTools/DumpRenderTree/TestNetscapePlugIn/Tests/NPRuntimeObjectFromDestroyedPlugin.cpp \ WebKitTools/DumpRenderTree/TestNetscapePlugIn/Tests/NPRuntimeRemoveProperty.cpp \ WebKitTools/DumpRenderTree/TestNetscapePlugIn/Tests/NullNPPGetValuePointer.cpp \ diff --git a/WebKitTools/MiniBrowser/mac/WebBundle/WebBundleMain.m b/WebKitTools/MiniBrowser/mac/WebBundle/WebBundleMain.m index 1fffce6..f3d44a5 100644 --- a/WebKitTools/MiniBrowser/mac/WebBundle/WebBundleMain.m +++ b/WebKitTools/MiniBrowser/mac/WebBundle/WebBundleMain.m @@ -88,7 +88,7 @@ void didRecieveMessage(WKBundleRef bundle, WKStringRef messageName, WKTypeRef me CFRelease(cfMessageName); } -void WKBundleInitialize(WKBundleRef bundle) +void WKBundleInitialize(WKBundleRef bundle, WKTypeRef initializationUserData) { globalBundle = bundle; diff --git a/WebKitTools/QtTestBrowser/QtTestBrowser.pro b/WebKitTools/QtTestBrowser/QtTestBrowser.pro index 08e0fb8..62d2c02 100644 --- a/WebKitTools/QtTestBrowser/QtTestBrowser.pro +++ b/WebKitTools/QtTestBrowser/QtTestBrowser.pro @@ -49,6 +49,7 @@ linux-* { symbian { TARGET.UID3 = 0xA000E543 TARGET.CAPABILITY = ReadUserData WriteUserData NetworkServices Location + MMP_RULES *= pageddata } contains(QT_CONFIG, opengl) { diff --git a/WebKitTools/QtTestBrowser/launcherwindow.cpp b/WebKitTools/QtTestBrowser/launcherwindow.cpp index e5e49be..7608063 100644 --- a/WebKitTools/QtTestBrowser/launcherwindow.cpp +++ b/WebKitTools/QtTestBrowser/launcherwindow.cpp @@ -70,12 +70,11 @@ void LauncherWindow::init() resize(800, 600); #endif - m_inspector = new WebInspector(splitter); + m_inspector = new WebInspector; #ifndef QT_NO_PROPERTIES if (!m_windowOptions.inspectorUrl.isEmpty()) m_inspector->setProperty("_q_inspectorUrl", m_windowOptions.inspectorUrl); #endif - m_inspector->hide(); connect(this, SIGNAL(destroyed()), m_inspector, SLOT(deleteLater())); // the zoom values are chosen to be like in Mozilla Firefox 3 @@ -130,6 +129,7 @@ void LauncherWindow::initializeView() applyPrefs(); + splitter->addWidget(m_inspector); m_inspector->setPage(page()); m_inspector->hide(); diff --git a/WebKitTools/QtTestBrowser/useragentlist.txt b/WebKitTools/QtTestBrowser/useragentlist.txt index b4b00f6..1c424d9 100644 --- a/WebKitTools/QtTestBrowser/useragentlist.txt +++ b/WebKitTools/QtTestBrowser/useragentlist.txt @@ -3,6 +3,7 @@ Mozilla/5.0 (SymbianOS/9.4; U; Series60/5.0; en-GB) AppleWebKit/533.3 (KHTML, li 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 (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 diff --git a/WebKitTools/QtTestBrowser/webinspector.h b/WebKitTools/QtTestBrowser/webinspector.h index d251c5c..5cc7f8a 100644 --- a/WebKitTools/QtTestBrowser/webinspector.h +++ b/WebKitTools/QtTestBrowser/webinspector.h @@ -35,7 +35,7 @@ class WebInspector : public QWebInspector { Q_OBJECT public: - WebInspector(QWidget* parent) : QWebInspector(parent) {} + WebInspector(QWidget* parent = 0) : QWebInspector(parent) {} signals: void visibleChanged(bool nowVisible); diff --git a/WebKitTools/QtTestBrowser/webview.cpp b/WebKitTools/QtTestBrowser/webview.cpp index 242daf6..fffaf9c 100644 --- a/WebKitTools/QtTestBrowser/webview.cpp +++ b/WebKitTools/QtTestBrowser/webview.cpp @@ -59,9 +59,26 @@ WebViewGraphicsBased::WebViewGraphicsBased(QWidget* parent) void WebViewGraphicsBased::setPage(QWebPage* page) { connect(page->mainFrame(), SIGNAL(contentsSizeChanged(const QSize&)), SLOT(contentsSizeChanged(const QSize&))); + connect(page, SIGNAL(scrollRequested(int, int, const QRect&)), SLOT(scrollRequested(int, int))); graphicsWebView()->setPage(page); } +void WebViewGraphicsBased::scrollRequested(int x, int y) +{ + if (!m_resizesToContents) + return; + + // Turn off interactive mode while scrolling, or QGraphicsView will replay the + // last mouse event which may cause WebKit to initiate a drag operation. + bool interactive = isInteractive(); + setInteractive(false); + + verticalScrollBar()->setValue(-y); + horizontalScrollBar()->setValue(-x); + + setInteractive(interactive); +} + void WebViewGraphicsBased::contentsSizeChanged(const QSize& size) { if (m_resizesToContents) diff --git a/WebKitTools/QtTestBrowser/webview.h b/WebKitTools/QtTestBrowser/webview.h index e34d081..240ea89 100644 --- a/WebKitTools/QtTestBrowser/webview.h +++ b/WebKitTools/QtTestBrowser/webview.h @@ -97,6 +97,7 @@ public slots: void animatedFlip(); void animatedYFlip(); void contentsSizeChanged(const QSize&); + void scrollRequested(int, int); signals: void currentFPSUpdated(int fps); diff --git a/WebKitTools/QueueStatusServer/__init__.py b/WebKitTools/QueueStatusServer/__init__.py new file mode 100644 index 0000000..2346c23 --- /dev/null +++ b/WebKitTools/QueueStatusServer/__init__.py @@ -0,0 +1,29 @@ +# Required for Python to search this directory for module files + +# This __init__.py makes unit testing easier by allowing us to treat the entire server as one big module. +# This file is only accessed when not on AppEngine itself. + +# Make sure that this module will load in that case by including paths to +# the default Google AppEngine install. + + +def fix_sys_path(): + import sys + import os + + # AppEngine imports a bunch of google-specific modules. Thankfully the dev_appserver + # knows how to do the same. Re-use the dev_appserver fix_sys_path logic to import + # all the google.appengine.* stuff so we can run under test-webkitpy + sys.path.append("/usr/local/google_appengine") + import dev_appserver + dev_appserver.fix_sys_path() + + # test-webkitpy adds $WEBKIT/WebKitTools to the sys.path and imports + # QueueStatusServer to run all the tests. However, when AppEngine runs + # our code QueueStatusServer is the root (and thus in the path). + # Emulate that here for test-webkitpy so that we can import "model." + # not "QueueStatusServer.model.", etc. + sys.path.append(os.path.dirname(__file__)) + + +fix_sys_path() diff --git a/WebKitTools/QueueStatusServer/handlers/queuestatus.py b/WebKitTools/QueueStatusServer/handlers/queuestatus.py index 5c31537..54c0fdd 100644 --- a/WebKitTools/QueueStatusServer/handlers/queuestatus.py +++ b/WebKitTools/QueueStatusServer/handlers/queuestatus.py @@ -26,11 +26,12 @@ # (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 itertools + from google.appengine.ext import webapp from google.appengine.ext.webapp import template from model.queues import Queue - from model import queuestatus @@ -49,6 +50,12 @@ class QueueStatus(webapp.RequestHandler): }) return rows + def _grouping_key_for_status(self, status): + return "%s-%s" % (status.active_patch_id, status.bot_id) + + def _build_status_groups(self, statuses): + return [list(group) for key, group in itertools.groupby(statuses, self._grouping_key_for_status)] + def get(self, queue_name): queue_name = queue_name.lower() queue = Queue.queue_with_name(queue_name) @@ -56,24 +63,10 @@ class QueueStatus(webapp.RequestHandler): self.error(404) return - status_groups = [] - last_patch_id = None - synthetic_patch_id_counter = 0 - statuses = queuestatus.QueueStatus.all().filter("queue_name =", queue.name()).order("-date").fetch(15) - for status in statuses: - patch_id = status.active_patch_id - if not patch_id or last_patch_id != patch_id: - status_group = [] - status_groups.append(status_group) - else: - status_group = status_groups[-1] - status_group.append(status) - last_patch_id = patch_id - template_values = { "display_queue_name": queue.display_name(), "work_item_rows": self._rows_for_work_items(queue), - "status_groups": status_groups, + "status_groups": self._build_status_groups(statuses), } self.response.out.write(template.render("templates/queuestatus.html", template_values)) diff --git a/WebKitTools/QueueStatusServer/handlers/queuestatus_unittest.py b/WebKitTools/QueueStatusServer/handlers/queuestatus_unittest.py new file mode 100644 index 0000000..a5ae844 --- /dev/null +++ b/WebKitTools/QueueStatusServer/handlers/queuestatus_unittest.py @@ -0,0 +1,62 @@ +# 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 Research in Motion Ltd. 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 handlers.queuestatus import QueueStatus +from model.queues import Queue + + +class MockStatus(object): + def __init__(self, patch_id, bot_id): + self.active_patch_id = patch_id + self.bot_id = bot_id + + +class QueueStatusTest(unittest.TestCase): + def test_build_status_groups(self): + queue_status = QueueStatus() + statuses = [ + MockStatus(1, "foo"), + MockStatus(1, "foo"), + MockStatus(2, "foo"), + MockStatus(1, "foo"), + MockStatus(1, "bar"), + MockStatus(1, "foo"), + ] + groups = queue_status._build_status_groups(statuses) + self.assertEqual(len(groups), 5) + self.assertEqual(groups[0], statuses[0:2]) + self.assertEqual(groups[1], statuses[2:3]) + self.assertEqual(groups[2], statuses[3:4]) + self.assertEqual(groups[3], statuses[4:5]) + self.assertEqual(groups[4], statuses[5:6]) + + +if __name__ == '__main__': + unittest.main() diff --git a/WebKitTools/QueueStatusServer/model/workitems.py b/WebKitTools/QueueStatusServer/model/workitems.py index fae6830..772fc39 100644 --- a/WebKitTools/QueueStatusServer/model/workitems.py +++ b/WebKitTools/QueueStatusServer/model/workitems.py @@ -52,6 +52,7 @@ class WorkItems(db.Model, QueuePropertyMixin): work_items.item_ids.append(attachment_id) work_items.put() + # Because this uses .key() self.is_saved() must be True or this will throw NotSavedError. def add_work_item(self, attachment_id): db.run_in_transaction(self._unguarded_add, self.key(), attachment_id) @@ -63,5 +64,6 @@ class WorkItems(db.Model, QueuePropertyMixin): work_items.item_ids.remove(attachment_id) work_items.put() + # Because this uses .key() self.is_saved() must be True or this will throw NotSavedError. def remove_work_item(self, attachment_id): db.run_in_transaction(self._unguarded_remove, self.key(), attachment_id) diff --git a/WebKitTools/QueueStatusServer/model/workitems_unittest.py b/WebKitTools/QueueStatusServer/model/workitems_unittest.py index d53302e..b1ff1d3 100644 --- a/WebKitTools/QueueStatusServer/model/workitems_unittest.py +++ b/WebKitTools/QueueStatusServer/model/workitems_unittest.py @@ -40,14 +40,6 @@ class WorkItemsTest(unittest.TestCase): self.assertEquals(items.display_position_for_attachment(1), 2) self.assertEquals(items.display_position_for_attachment(3), None) - def test_remove_work_item(self): - items = WorkItems() - items.item_ids = [0, 1, 2] - items.remove_work_item(0) - self.assertEqual(items.item_ids, [1, 2]) - items.remove_work_item(4) # Should not throw - self.assertEqual(items.item_ids, [1, 2]) - if __name__ == '__main__': unittest.main() diff --git a/WebKitTools/QueueStatusServer/templates/includes/singlequeuestatus.html b/WebKitTools/QueueStatusServer/templates/includes/singlequeuestatus.html index 075cd39..0adbfbd 100644 --- a/WebKitTools/QueueStatusServer/templates/includes/singlequeuestatus.html +++ b/WebKitTools/QueueStatusServer/templates/includes/singlequeuestatus.html @@ -1,4 +1,8 @@ -<span class="status-date">{{ status.date|timesince }} ago</span> +<span class="status-date">{{ status.date|timesince }} ago +{% if status.bot_id %} +({{ status.bot_id }}) +{% endif %} +</span> <span class="status-message">{{ status.message|force_escape|urlize|webkit_linkify|safe }}</span> {% if status.results_file %} <span class="status-results">[{{ status.key.id|results_link|safe }}]</span> diff --git a/WebKitTools/Scripts/check-webkit-style b/WebKitTools/Scripts/check-webkit-style index e29d4b1..076c712 100755 --- a/WebKitTools/Scripts/check-webkit-style +++ b/WebKitTools/Scripts/check-webkit-style @@ -112,10 +112,11 @@ def main(): file_reader = TextFileReader(style_processor) - if paths: + if paths and not options.diff_files: file_reader.process_paths(paths) else: - patch = checkout.create_patch(options.git_commit) + changed_files = paths if options.diff_files else None + patch = checkout.create_patch(options.git_commit, changed_files=changed_files) patch_checker = PatchReader(file_reader) patch_checker.check(patch) diff --git a/WebKitTools/Scripts/old-run-webkit-tests b/WebKitTools/Scripts/old-run-webkit-tests index e40b3ad..2cef18b 100755 --- a/WebKitTools/Scripts/old-run-webkit-tests +++ b/WebKitTools/Scripts/old-run-webkit-tests @@ -373,6 +373,8 @@ if ($useWebKitTestRunner) { } } +$timeoutSeconds *= 10 if $guardMalloc; + $stripEditingCallbacks = isCygwin() unless defined $stripEditingCallbacks; my $ignoreSkipped = $treatSkipped eq "ignore"; @@ -1483,6 +1485,12 @@ sub openDumpTool() unshift @args, "valgrind", "--suppressions=$platformBaseDirectory/qt/SuppressedValgrindErrors"; } + if ($useWebKitTestRunner) { + # Make WebKitTestRunner use a similar timeout. We don't use the exact same timeout to avoid + # race conditions. + push @args, "--timeout", $timeoutSeconds - 5; + } + $CLEAN_ENV{MallocStackLogging} = 1 if $shouldCheckLeaks; $dumpToolPID = open3(\*OUT, \*IN, \*ERROR, launchWithEnv(@args, %CLEAN_ENV)) or die "Failed to start tool: $dumpTool\n"; @@ -2089,7 +2097,6 @@ sub readFromDumpToolWithTimer(**) setFileHandleNonBlocking($fhError, 1); my $maximumSecondsWithoutOutput = $timeoutSeconds; - $maximumSecondsWithoutOutput *= 10 if $guardMalloc; my $microsecondsToWaitBeforeReadingAgain = 1000; my $timeOfLastSuccessfulRead = time; diff --git a/WebKitTools/Scripts/webkitpy/common/checkout/scm.py b/WebKitTools/Scripts/webkitpy/common/checkout/scm.py index 9b602c3..8aadcb8 100644 --- a/WebKitTools/Scripts/webkitpy/common/checkout/scm.py +++ b/WebKitTools/Scripts/webkitpy/common/checkout/scm.py @@ -64,7 +64,7 @@ def default_scm(): cwd = os.getcwd() scm_system = detect_scm_system(cwd) if not scm_system: - script_directory = os.path.abspath(sys.path[0]) + script_directory = os.path.dirname(os.path.abspath(__file__)) scm_system = detect_scm_system(script_directory) if scm_system: log("The current directory (%s) is not a WebKit checkout, using %s" % (cwd, scm_system.checkout_root)) diff --git a/WebKitTools/Scripts/webkitpy/common/config/committers.py b/WebKitTools/Scripts/webkitpy/common/config/committers.py index 71d764c..446c2b1 100644 --- a/WebKitTools/Scripts/webkitpy/common/config/committers.py +++ b/WebKitTools/Scripts/webkitpy/common/config/committers.py @@ -112,6 +112,7 @@ committers_unable_to_review = [ Committer("Girish Ramakrishnan", ["girish@forwardbias.in", "ramakrishnan.girish@gmail.com"]), Committer("Graham Dennis", ["Graham.Dennis@gmail.com", "gdennis@webkit.org"]), Committer("Greg Bolsinga", "bolsinga@apple.com"), + Committer("Gyuyoung Kim", ["gyuyoung.kim@samsung.com", "gyuyoung@gmail.com", "gyuyoung@webkit.org"], "gyuyoung"), Committer("Hans Wennborg", "hans@chromium.org", "hwennborg"), Committer("Hayato Ito", "hayato@chromium.org", "hayato"), Committer("Hin-Chung Lam", ["hclam@google.com", "hclam@chromium.org"]), @@ -147,7 +148,7 @@ committers_unable_to_review = [ Committer("Luiz Agostini", ["luiz@webkit.org", "luiz.agostini@openbossa.org"], "lca"), Committer("Mads Ager", "ager@chromium.org"), Committer("Marcus Voltis Bulach", "bulach@chromium.org"), - Committer("Mario Sanchez Prada", ["msanchez@igalia.com", "mario@webkit.org"]), + Committer("Mario Sanchez Prada", ["msanchez@igalia.com", "mario@webkit.org"], "msanchez"), Committer("Matt Delaney", "mdelaney@apple.com"), Committer("Matt Lilek", ["webkit@mattlilek.com", "pewtermoose@webkit.org"]), Committer("Matt Perry", "mpcomplete@chromium.org"), @@ -171,6 +172,7 @@ committers_unable_to_review = [ Committer("Philippe Normand", ["pnormand@igalia.com", "philn@webkit.org"], "philn-tp"), Committer("Pierre d'Herbemont", ["pdherbemont@free.fr", "pdherbemont@apple.com"], "pdherbemont"), Committer("Pierre-Olivier Latour", "pol@apple.com", "pol"), + Committer("Renata Hodovan", "reni@webkit.org", "reni"), Committer("Robert Hogan", ["robert@webkit.org", "robert@roberthogan.net", "lists@roberthogan.net"], "mwenge"), Committer("Roland Steiner", "rolandsteiner@chromium.org"), Committer("Ryosuke Niwa", "rniwa@webkit.org", "rniwa"), diff --git a/WebKitTools/Scripts/webkitpy/common/net/bugzilla.py b/WebKitTools/Scripts/webkitpy/common/net/bugzilla.py index 1cc8e2e..a7dc1b7 100644 --- a/WebKitTools/Scripts/webkitpy/common/net/bugzilla.py +++ b/WebKitTools/Scripts/webkitpy/common/net/bugzilla.py @@ -281,7 +281,7 @@ class BugzillaQueries(object): return sum([self._fetch_bug(bug_id).commit_queued_patches() for bug_id in self.fetch_bug_ids_from_commit_queue()], []) - def _fetch_bug_ids_from_review_queue(self): + def fetch_bug_ids_from_review_queue(self): review_queue_url = "buglist.cgi?query_format=advanced&bug_status=UNCONFIRMED&bug_status=NEW&bug_status=ASSIGNED&bug_status=REOPENED&field0-0-0=flagtypes.name&type0-0-0=equals&value0-0-0=review?" return self._fetch_bug_ids_advanced_query(review_queue_url) @@ -289,7 +289,7 @@ class BugzillaQueries(object): def fetch_patches_from_review_queue(self, limit=None): # [:None] returns the whole array. return sum([self._fetch_bug(bug_id).unreviewed_patches() - for bug_id in self._fetch_bug_ids_from_review_queue()[:limit]], []) + for bug_id in self.fetch_bug_ids_from_review_queue()[:limit]], []) # NOTE: This is the only client of _fetch_attachment_ids_request_query # This method only makes one request to bugzilla. diff --git a/WebKitTools/Scripts/webkitpy/common/system/executive.py b/WebKitTools/Scripts/webkitpy/common/system/executive.py index 216cf58..37f4e53 100644 --- a/WebKitTools/Scripts/webkitpy/common/system/executive.py +++ b/WebKitTools/Scripts/webkitpy/common/system/executive.py @@ -33,6 +33,7 @@ try: except ImportError: multiprocessing = None +import ctypes import errno import logging import os @@ -44,6 +45,7 @@ import sys import time from webkitpy.common.system.deprecated_logging import tee +from webkitpy.python24 import versioning _log = logging.getLogger("webkitpy.common.system") @@ -103,13 +105,8 @@ class Executive(object): def _run_command_with_teed_output(self, args, teed_output): args = map(unicode, args) # Popen will throw an exception if args are non-strings (like int()) - if sys.platform == 'cygwin': - # Cygwin's Python's os.execv doesn't support unicode command - # arguments, and neither does Cygwin's execv itself. - # FIXME: Using UTF-8 here will confuse Windows-native commands - # which will expect arguments to be encoded using the current code - # page. - args = [arg.encode('utf-8') for arg in args] + args = map(self._encode_argument_if_needed, args) + child_process = subprocess.Popen(args, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, @@ -148,9 +145,8 @@ class Executive(object): child_output = child_out_file.getvalue() child_out_file.close() - # We assume the child process output utf-8 if decode_output: - child_output = child_output.decode("utf-8") + child_output = child_output.decode(self._child_process_encoding()) if exit_code: raise ScriptError(script_args=args, @@ -205,6 +201,55 @@ class Executive(object): return raise + def _win32_check_running_pid(self): + + class PROCESSENTRY32(ctypes.Structure): + _fields_ = [("dwSize", ctypes.c_ulong), + ("cntUsage", ctypes.c_ulong), + ("th32ProcessID", ctypes.c_ulong), + ("th32DefaultHeapID", ctypes.c_ulong), + ("th32ModuleID", ctypes.c_ulong), + ("cntThreads", ctypes.c_ulong), + ("th32ParentProcessID", ctypes.c_ulong), + ("pcPriClassBase", ctypes.c_ulong), + ("dwFlags", ctypes.c_ulong), + ("szExeFile", ctypes.c_char * 260)] + + CreateToolhelp32Snapshot = ctypes.windll.kernel32.CreateToolhelp32Snapshot + Process32First = ctypes.windll.kernel32.Process32First + Process32Next = ctypes.windll.kernel32.Process32Next + CloseHandle = ctypes.windll.kernel32.CloseHandle + TH32CS_SNAPPROCESS = 0x00000002 # win32 magic number + hProcessSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0) + pe32 = PROCESSENTRY32() + pe32.dwSize = ctypes.sizeof(PROCESSENTRY32) + result = False + if not Process32First(hProcessSnap, ctypes.byref(pe32)): + _log.debug("Failed getting first process.") + CloseHandle(hProcessSnap) + return result + while True: + if pe32.th32ProcessID == pid: + result = True + break + if not Process32Next(hProcessSnap, ctypes.byref(pe32)): + break + CloseHandle(hProcessSnap) + return result + + def check_running_pid(self, pid): + """Return True if pid is alive, otherwise return False.""" + if sys.platform in ('darwin', 'linux2', 'cygwin'): + try: + os.kill(pid, 0) + return True + except OSError: + return False + elif sys.platform == 'win32': + return self._win32_check_running_pid() + + assert(False) + def _windows_image_name(self, process_name): name, extension = os.path.splitext(process_name) if not extension: @@ -260,7 +305,7 @@ class Executive(object): # for an example of a regresion caused by passing a unicode string directly. # FIXME: We may need to encode differently on different platforms. if isinstance(input, unicode): - input = input.encode("utf-8") + input = input.encode(self._child_process_encoding()) return (subprocess.PIPE, input) def _command_for_printing(self, args): @@ -288,13 +333,8 @@ class Executive(object): assert(isinstance(args, list) or isinstance(args, tuple)) start_time = time.time() args = map(unicode, args) # Popen will throw an exception if args are non-strings (like int()) - if sys.platform == 'cygwin': - # Cygwin's Python's os.execv doesn't support unicode command - # arguments, and neither does Cygwin's execv itself. - # FIXME: Using UTF-8 here will confuse Windows-native commands - # which will expect arguments to be encoded using the current code - # page. - args = [arg.encode('utf-8') for arg in args] + args = map(self._encode_argument_if_needed, args) + stdin, string_to_communicate = self._compute_stdin(input) stderr = subprocess.STDOUT if return_stderr else None @@ -305,9 +345,11 @@ class Executive(object): cwd=cwd, close_fds=self._should_close_fds()) output = process.communicate(string_to_communicate)[0] + # run_command automatically decodes to unicode() unless explicitly told not to. if decode_output: - output = output.decode("utf-8") + output = output.decode(self._child_process_encoding()) + # wait() is not threadsafe and can throw OSError due to: # http://bugs.python.org/issue1731717 exit_code = process.wait() @@ -324,3 +366,34 @@ class Executive(object): cwd=cwd) (error_handler or self.default_error_handler)(script_error) return output + + def _child_process_encoding(self): + # Win32 Python 2.x uses CreateProcessA rather than CreateProcessW + # to launch subprocesses, so we have to encode arguments using the + # current code page. + if sys.platform == 'win32' and versioning.compare_version(sys, '3.0')[0] < 0: + return 'mbcs' + # All other platforms use UTF-8. + # FIXME: Using UTF-8 on Cygwin will confuse Windows-native commands + # which will expect arguments to be encoded using the current code + # page. + return 'utf-8' + + def _should_encode_child_process_arguments(self): + # Cygwin's Python's os.execv doesn't support unicode command + # arguments, and neither does Cygwin's execv itself. + if sys.platform == 'cygwin': + return True + + # Win32 Python 2.x uses CreateProcessA rather than CreateProcessW + # to launch subprocesses, so we have to encode arguments using the + # current code page. + if sys.platform == 'win32' and versioning.compare_version(sys, '3.0')[0] < 0: + return True + + return False + + def _encode_argument_if_needed(self, argument): + if not self._should_encode_child_process_arguments(): + return argument + return argument.encode(self._child_process_encoding()) diff --git a/WebKitTools/Scripts/webkitpy/common/system/executive_unittest.py b/WebKitTools/Scripts/webkitpy/common/system/executive_unittest.py index 32f8f51..b8fd82e 100644 --- a/WebKitTools/Scripts/webkitpy/common/system/executive_unittest.py +++ b/WebKitTools/Scripts/webkitpy/common/system/executive_unittest.py @@ -27,12 +27,23 @@ # (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 os import signal import subprocess import sys import unittest from webkitpy.common.system.executive import Executive, run_command, ScriptError +from webkitpy.test import cat, echo + + +def never_ending_command(): + """Arguments for a command that will never end (useful for testing process + killing). It should be a process that is unlikely to already be running + because all instances will be killed.""" + if sys.platform == 'win32': + return ['wmic'] + return ['yes'] class ExecutiveTest(unittest.TestCase): @@ -46,46 +57,56 @@ class ExecutiveTest(unittest.TestCase): executive = Executive() self.assertRaises(AssertionError, executive.run_command, "echo") self.assertRaises(AssertionError, executive.run_command, u"echo") - executive.run_command(["echo", "foo"]) - executive.run_command(("echo", "foo")) + executive.run_command(echo.command_arguments('foo')) + executive.run_command(tuple(echo.command_arguments('foo'))) def test_run_command_with_unicode(self): """Validate that it is safe to pass unicode() objects to Executive.run* methods, and they will return unicode() objects by default unless decode_output=False""" + unicode_tor_input = u"WebKit \u2661 Tor Arne Vestb\u00F8!" + if sys.platform == 'win32': + encoding = 'mbcs' + else: + encoding = 'utf-8' + encoded_tor = unicode_tor_input.encode(encoding) + # On Windows, we expect the unicode->mbcs->unicode roundtrip to be + # lossy. On other platforms, we expect a lossless roundtrip. + if sys.platform == 'win32': + unicode_tor_output = encoded_tor.decode(encoding) + else: + unicode_tor_output = unicode_tor_input + executive = Executive() - unicode_tor = u"WebKit \u2661 Tor Arne Vestb\u00F8!" - utf8_tor = unicode_tor.encode("utf-8") - output = executive.run_command(["cat"], input=unicode_tor) - self.assertEquals(output, unicode_tor) + output = executive.run_command(cat.command_arguments(), input=unicode_tor_input) + self.assertEquals(output, unicode_tor_output) - output = executive.run_command(["echo", "-n", unicode_tor]) - self.assertEquals(output, unicode_tor) + output = executive.run_command(echo.command_arguments("-n", unicode_tor_input)) + self.assertEquals(output, unicode_tor_output) - output = executive.run_command(["echo", "-n", unicode_tor], decode_output=False) - self.assertEquals(output, utf8_tor) + output = executive.run_command(echo.command_arguments("-n", unicode_tor_input), decode_output=False) + self.assertEquals(output, encoded_tor) # Make sure that str() input also works. - output = executive.run_command(["cat"], input=utf8_tor, decode_output=False) - self.assertEquals(output, utf8_tor) + output = executive.run_command(cat.command_arguments(), input=encoded_tor, decode_output=False) + self.assertEquals(output, encoded_tor) # FIXME: We should only have one run* method to test - output = executive.run_and_throw_if_fail(["echo", "-n", unicode_tor], quiet=True) - self.assertEquals(output, unicode_tor) + output = executive.run_and_throw_if_fail(echo.command_arguments("-n", unicode_tor_input), quiet=True) + self.assertEquals(output, unicode_tor_output) - output = executive.run_and_throw_if_fail(["echo", "-n", unicode_tor], quiet=True, decode_output=False) - self.assertEquals(output, utf8_tor) + output = executive.run_and_throw_if_fail(echo.command_arguments("-n", unicode_tor_input), quiet=True, decode_output=False) + self.assertEquals(output, encoded_tor) def test_kill_process(self): executive = Executive() - # We use "yes" because it loops forever. - process = subprocess.Popen(["yes"], stdout=subprocess.PIPE) + process = subprocess.Popen(never_ending_command(), stdout=subprocess.PIPE) self.assertEqual(process.poll(), None) # Process is running executive.kill_process(process.pid) # Note: Can't use a ternary since signal.SIGKILL is undefined for sys.platform == "win32" if sys.platform == "win32": - expected_exit_code = 0 # taskkill.exe results in exit(0) + expected_exit_code = 1 else: expected_exit_code = -signal.SIGKILL self.assertEqual(process.wait(), expected_exit_code) @@ -109,14 +130,22 @@ class ExecutiveTest(unittest.TestCase): def test_kill_all(self): executive = Executive() # We use "yes" because it loops forever. - process = subprocess.Popen(["yes"], stdout=subprocess.PIPE) + process = subprocess.Popen(never_ending_command(), stdout=subprocess.PIPE) self.assertEqual(process.poll(), None) # Process is running - executive.kill_all("yes") + executive.kill_all(never_ending_command()[0]) # Note: Can't use a ternary since signal.SIGTERM is undefined for sys.platform == "win32" - if sys.platform in ("win32", "cygwin"): - expected_exit_code = 0 # taskkill.exe results in exit(0) + if sys.platform == "cygwin": + expected_exit_code = 0 # os.kill results in exit(0) for this process. + elif sys.platform == "win32": + expected_exit_code = 1 else: expected_exit_code = -signal.SIGTERM self.assertEqual(process.wait(), expected_exit_code) # Killing again should fail silently. - executive.kill_all("yes") + executive.kill_all(never_ending_command()[0]) + + def test_check_running_pid(self): + executive = Executive() + self.assertTrue(executive.check_running_pid(os.getpid())) + # Maximum pid number on Linux is 32768 by default + self.assertFalse(executive.check_running_pid(100000)) diff --git a/WebKitTools/Scripts/webkitpy/common/system/filesystem.py b/WebKitTools/Scripts/webkitpy/common/system/filesystem.py new file mode 100644 index 0000000..c7efde3 --- /dev/null +++ b/WebKitTools/Scripts/webkitpy/common/system/filesystem.py @@ -0,0 +1,117 @@ +# 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. + +"""Wrapper object for the file system / source tree.""" + +from __future__ import with_statement + +import codecs +import errno +import os +import tempfile + + +class FileSystem(object): + """FileSystem interface for webkitpy. + + Unless otherwise noted, all paths are allowed to be either absolute + or relative.""" + + def exists(self, path): + """Return whether the path exists in the filesystem.""" + return os.path.exists(path) + + def isdir(self, path): + """Return whether the path refers to a directory.""" + return os.path.isdir(path) + + def join(self, *comps): + """Return the path formed by joining the components.""" + return os.path.join(*comps) + + def listdir(self, path): + """Return the contents of the directory pointed to by path.""" + return os.listdir(path) + + def mkdtemp(self, **kwargs): + """Create and return a uniquely named directory. + + This is like tempfile.mkdtemp, but if used in a with statement + the directory will self-delete at the end of the block (if the + directory is empty; non-empty directories raise errors). The + directory can be safely deleted inside the block as well, if so + desired.""" + class TemporaryDirectory(object): + def __init__(self, **kwargs): + self._kwargs = kwargs + self._directory_path = None + + def __enter__(self): + self._directory_path = tempfile.mkdtemp(**self._kwargs) + return self._directory_path + + def __exit__(self, type, value, traceback): + # Only self-delete if necessary. + + # FIXME: Should we delete non-empty directories? + if os.path.exists(self._directory_path): + os.rmdir(self._directory_path) + + return TemporaryDirectory(**kwargs) + + def maybe_make_directory(self, *path): + """Create the specified directory if it doesn't already exist.""" + try: + os.makedirs(os.path.join(*path)) + except OSError, e: + if e.errno != errno.EEXIST: + raise + + def read_binary_file(self, path): + """Return the contents of the file at the given path as a byte string.""" + with file(path, 'rb') as f: + return f.read() + + def read_text_file(self, path): + """Return the contents of the file at the given path as a Unicode string. + + The file is read assuming it is a UTF-8 encoded file with no BOM.""" + with codecs.open(path, 'r', 'utf8') as f: + return f.read() + + def write_binary_file(self, path, contents): + """Write the contents to the file at the given location.""" + with file(path, 'wb') as f: + f.write(contents) + + def write_text_file(self, path, contents): + """Write the contents to the file at the given location. + + The file is written encoded as UTF-8 with no BOM.""" + with codecs.open(path, 'w', 'utf8') as f: + f.write(contents) diff --git a/WebKitTools/Scripts/webkitpy/common/system/filesystem_unittest.py b/WebKitTools/Scripts/webkitpy/common/system/filesystem_unittest.py new file mode 100644 index 0000000..95684b7 --- /dev/null +++ b/WebKitTools/Scripts/webkitpy/common/system/filesystem_unittest.py @@ -0,0 +1,157 @@ +# vim: set fileencoding=utf-8 : +# 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. + +# NOTE: The fileencoding comment on the first line of the file is +# important; without it, Python will choke while trying to parse the file, +# since it includes non-ASCII characters. + +from __future__ import with_statement + +import os +import stat +import sys +import tempfile +import unittest + +from filesystem import FileSystem + + +class FileSystemTest(unittest.TestCase): + def setUp(self): + self._this_dir = os.path.dirname(os.path.abspath(__file__)) + 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_exists__true(self): + fs = FileSystem() + self.assertTrue(fs.exists(self._this_file)) + + def test_exists__false(self): + fs = FileSystem() + self.assertFalse(fs.exists(self._missing_file)) + + def test_isdir__true(self): + fs = FileSystem() + self.assertTrue(fs.isdir(self._this_dir)) + + def test_isdir__false(self): + fs = FileSystem() + self.assertFalse(fs.isdir(self._this_file)) + + def test_join(self): + fs = FileSystem() + self.assertEqual(fs.join('foo', 'bar'), + os.path.join('foo', 'bar')) + + def test_listdir(self): + fs = FileSystem() + with fs.mkdtemp(prefix='filesystem_unittest_') as d: + self.assertEqual(fs.listdir(d), []) + new_file = os.path.join(d, 'foo') + fs.write_text_file(new_file, u'foo') + self.assertEqual(fs.listdir(d), ['foo']) + os.remove(new_file) + + def test_maybe_make_directory__success(self): + fs = FileSystem() + + with fs.mkdtemp(prefix='filesystem_unittest_') as base_path: + sub_path = os.path.join(base_path, "newdir") + self.assertFalse(os.path.exists(sub_path)) + self.assertFalse(fs.isdir(sub_path)) + + fs.maybe_make_directory(sub_path) + self.assertTrue(os.path.exists(sub_path)) + self.assertTrue(fs.isdir(sub_path)) + + # Make sure we can re-create it. + fs.maybe_make_directory(sub_path) + self.assertTrue(os.path.exists(sub_path)) + self.assertTrue(fs.isdir(sub_path)) + + # Clean up. + os.rmdir(sub_path) + + self.assertFalse(os.path.exists(base_path)) + self.assertFalse(fs.isdir(base_path)) + + def test_maybe_make_directory__failure(self): + # FIXME: os.chmod() doesn't work on Windows to set directories + # as readonly, so we skip this test for now. + if sys.platform in ('win32', 'cygwin'): + return + + fs = FileSystem() + with fs.mkdtemp(prefix='filesystem_unittest_') as d: + # Remove write permissions on the parent directory. + os.chmod(d, stat.S_IRUSR) + + # Now try to create a sub directory - should fail. + sub_dir = fs.join(d, 'subdir') + self.assertRaises(OSError, fs.maybe_make_directory, sub_dir) + + # Clean up in case the test failed and we did create the + # directory. + if os.path.exists(sub_dir): + os.rmdir(sub_dir) + + def test_read_and_write_file(self): + fs = FileSystem() + text_path = None + binary_path = None + + unicode_text_string = u'Ūnĭcōde̽' + hex_equivalent = '\xC5\xAA\x6E\xC4\xAD\x63\xC5\x8D\x64\x65\xCC\xBD' + try: + text_path = tempfile.mktemp(prefix='tree_unittest_') + binary_path = tempfile.mktemp(prefix='tree_unittest_') + fs.write_text_file(text_path, unicode_text_string) + contents = fs.read_binary_file(text_path) + self.assertEqual(contents, hex_equivalent) + + fs.write_text_file(binary_path, hex_equivalent) + text_contents = fs.read_text_file(binary_path) + self.assertEqual(text_contents, unicode_text_string) + except: + if text_path: + os.remove(text_path) + if binary_path: + os.remove(binary_path) + + def test_read_binary_file__missing(self): + fs = FileSystem() + self.assertRaises(IOError, fs.read_binary_file, self._missing_file) + + def test_read_text_file__missing(self): + fs = FileSystem() + self.assertRaises(IOError, fs.read_text_file, self._missing_file) + + +if __name__ == '__main__': + unittest.main() diff --git a/WebKitTools/Scripts/webkitpy/common/system/fileutils.py b/WebKitTools/Scripts/webkitpy/common/system/fileutils.py new file mode 100644 index 0000000..55821f8 --- /dev/null +++ b/WebKitTools/Scripts/webkitpy/common/system/fileutils.py @@ -0,0 +1,33 @@ +# 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. + +import sys + + +def make_stdout_binary(): + """Puts sys.stdout into binary mode (on platforms that have a distinction + between text and binary mode).""" + if sys.platform != 'win32' or not hasattr(sys.stdout, 'fileno'): + return + import msvcrt + import os + msvcrt.setmode(sys.stdout.fileno(), os.O_BINARY) diff --git a/WebKitTools/Scripts/webkitpy/common/system/path.py b/WebKitTools/Scripts/webkitpy/common/system/path.py index 43c6410..09787d7 100644 --- a/WebKitTools/Scripts/webkitpy/common/system/path.py +++ b/WebKitTools/Scripts/webkitpy/common/system/path.py @@ -44,7 +44,7 @@ def abspath_to_uri(path, platform=None): def cygpath(path): - """Converts a cygwin path to Windows path.""" + """Converts an absolute cygwin path to an absolute Windows path.""" return _CygPath.convert_using_singleton(path) @@ -103,7 +103,11 @@ class _CygPath(object): self.start() self._child_process.stdin.write("%s\r\n" % path) self._child_process.stdin.flush() - return self._child_process.stdout.readline().rstrip() + windows_path = self._child_process.stdout.readline().rstrip() + # Some versions of cygpath use lowercase drive letters while others + # use uppercase. We always convert to uppercase for consistency. + windows_path = '%s%s' % (windows_path[0].upper(), windows_path[1:]) + return windows_path def _escape(path): diff --git a/WebKitTools/Scripts/webkitpy/layout_tests/layout_package/dump_render_tree_thread.py b/WebKitTools/Scripts/webkitpy/layout_tests/layout_package/dump_render_tree_thread.py index 3e3ba0b..9f2de7e 100644 --- a/WebKitTools/Scripts/webkitpy/layout_tests/layout_package/dump_render_tree_thread.py +++ b/WebKitTools/Scripts/webkitpy/layout_tests/layout_package/dump_render_tree_thread.py @@ -341,7 +341,7 @@ class TestShellThread(WatchableThread): def cancel(self): """Clean up http lock and set a flag telling this thread to quit.""" - self._stop_http_lock() + self._stop_servers_with_lock() WatchableThread.cancel(self) def next_timeout(self): @@ -389,23 +389,15 @@ class TestShellThread(WatchableThread): self._current_group, self._filename_list = \ self._filename_list_queue.get_nowait() except Queue.Empty: - self._stop_http_lock() + self._stop_servers_with_lock() self._kill_dump_render_tree() tests_run_file.close() return - if self._options.wait_for_httpd: - if self._current_group == "tests_to_http_lock": - self._http_lock_wait_begin = time.time() - self._port.acquire_http_lock() - - self._port.start_http_server() - self._port.start_websocket_server() - - self._have_http_lock = True - self._http_lock_wait_end = time.time() - elif self._have_http_lock: - self._stop_http_lock() + if self._current_group == "tests_to_http_lock": + self._start_servers_with_lock() + elif self._have_http_lock: + self._stop_servers_with_lock() self._num_tests_in_current_group = len(self._filename_list) self._current_group_start_time = time.time() @@ -440,7 +432,7 @@ class TestShellThread(WatchableThread): self._port.relative_test_filename(filename))) self._result_queue.put(result.dumps()) - if batch_size > 0 and batch_count > batch_size: + if batch_size > 0 and batch_count >= batch_size: # Bounce the shell and reset count. self._kill_dump_render_tree() batch_count = 0 @@ -545,11 +537,26 @@ class TestShellThread(WatchableThread): self._options) self._driver.start() - def _stop_http_lock(self): + def _start_servers_with_lock(self): + """Acquire http lock and start the servers.""" + self._http_lock_wait_begin = time.time() + _log.debug('Acquire http lock ...') + self._port.acquire_http_lock() + _log.debug('Starting HTTP server ...') + self._port.start_http_server() + _log.debug('Starting WebSocket server ...') + self._port.start_websocket_server() + self._http_lock_wait_end = time.time() + self._have_http_lock = True + + def _stop_servers_with_lock(self): """Stop the servers and release http lock.""" if self._have_http_lock: + _log.debug('Stopping HTTP server ...') self._port.stop_http_server() + _log.debug('Stopping WebSocket server ...') self._port.stop_websocket_server() + _log.debug('Release http lock ...') self._port.release_http_lock() self._have_http_lock = False diff --git a/WebKitTools/Scripts/webkitpy/layout_tests/port/base.py b/WebKitTools/Scripts/webkitpy/layout_tests/port/base.py index cd7d663..a98b858 100644 --- a/WebKitTools/Scripts/webkitpy/layout_tests/port/base.py +++ b/WebKitTools/Scripts/webkitpy/layout_tests/port/base.py @@ -47,6 +47,7 @@ import http_server import test_files import websocket_server +from webkitpy.common.memoized import memoized from webkitpy.common.system import logutils from webkitpy.common.system.executive import Executive, ScriptError from webkitpy.common.system.path import abspath_to_uri @@ -725,13 +726,25 @@ class Port(object): e.message_with_output())) return self._pretty_patch_error_html - def _webkit_build_directory(self, args): - args = ["perl", self.script_path("webkit-build-directory")] + args + def _webkit_build_directory_command(self, args): + return ["perl", self.script_path("webkit-build-directory")] + args + + @memoized + def _webkit_top_level_build_directory(self, top_level=True): + """This directory is above where products are built to and contains things like the Configuration file.""" + args = self._webkit_build_directory_command(["--top-level"]) + return self._executive.run_command(args).rstrip() + + @memoized + def _webkit_configuration_build_directory(self, configuration=None): + """This is where products are normally built to.""" + if not configuration: + configuration = self.flag_from_configuration(self.get_option('configuration')) + args = self._webkit_build_directory_command(["--configuration", configuration]) return self._executive.run_command(args).rstrip() def _configuration_file_path(self): - build_root = self._webkit_build_directory(["--top-level"]) - return os.path.join(build_root, "Configuration") + return os.path.join(self._webkit_top_level_build_directory(), "Configuration") # Easy override for unit tests def _open_configuration_file(self): diff --git a/WebKitTools/Scripts/webkitpy/layout_tests/port/chromium_gpu.py b/WebKitTools/Scripts/webkitpy/layout_tests/port/chromium_gpu.py index 5d28fae..57b6989 100644 --- a/WebKitTools/Scripts/webkitpy/layout_tests/port/chromium_gpu.py +++ b/WebKitTools/Scripts/webkitpy/layout_tests/port/chromium_gpu.py @@ -71,6 +71,8 @@ def _set_gpu_options(options): options.accelerated_2d_canvas = True if options.builder_name is not None: options.builder_name = options.builder_name + ' - GPU' + if options.use_drt is None: + options.use_drt = True def _gpu_overrides(port): @@ -96,6 +98,9 @@ class ChromiumGpuLinuxPort(chromium_linux.ChromiumLinuxPort): return (map(self._webkit_baseline_path, ['chromium-gpu-linux', 'chromium-gpu-win', 'chromium-gpu']) + chromium_linux.ChromiumLinuxPort.baseline_search_path(self)) + def default_child_processes(self): + return 1 + def path_to_test_expectations_file(self): return self.path_from_webkit_base('LayoutTests', 'platform', 'chromium-gpu', 'test_expectations.txt') @@ -114,6 +119,9 @@ class ChromiumGpuMacPort(chromium_mac.ChromiumMacPort): return (map(self._webkit_baseline_path, ['chromium-gpu-mac', 'chromium-gpu']) + chromium_mac.ChromiumMacPort.baseline_search_path(self)) + def default_child_processes(self): + return 1 + def path_to_test_expectations_file(self): return self.path_from_webkit_base('LayoutTests', 'platform', 'chromium-gpu', 'test_expectations.txt') @@ -132,6 +140,9 @@ class ChromiumGpuWinPort(chromium_win.ChromiumWinPort): return (map(self._webkit_baseline_path, ['chromium-gpu-win', 'chromium-gpu']) + chromium_win.ChromiumWinPort.baseline_search_path(self)) + def default_child_processes(self): + return 1 + def path_to_test_expectations_file(self): return self.path_from_webkit_base('LayoutTests', 'platform', 'chromium-gpu', 'test_expectations.txt') diff --git a/WebKitTools/Scripts/webkitpy/layout_tests/port/chromium_gpu_unittest.py b/WebKitTools/Scripts/webkitpy/layout_tests/port/chromium_gpu_unittest.py index 88524fc..03bc98a 100644 --- a/WebKitTools/Scripts/webkitpy/layout_tests/port/chromium_gpu_unittest.py +++ b/WebKitTools/Scripts/webkitpy/layout_tests/port/chromium_gpu_unittest.py @@ -45,10 +45,14 @@ class ChromiumGpuTest(unittest.TestCase): # test that we got the right port mock_options = mocktool.MockOptions(accelerated_compositing=None, accelerated_2d_canvas=None, - builder_name='foo') + builder_name='foo', + use_drt=None, + child_processes=None) port = chromium_gpu.get(port_name=port_name, options=mock_options) self.assertTrue(port._options.accelerated_compositing) self.assertTrue(port._options.accelerated_2d_canvas) + self.assertTrue(port._options.use_drt) + self.assertEqual(port.default_child_processes(), 1) self.assertEqual(port._options.builder_name, 'foo - GPU') # we use startswith() instead of Equal to gloss over platform versions. diff --git a/WebKitTools/Scripts/webkitpy/layout_tests/port/config.py b/WebKitTools/Scripts/webkitpy/layout_tests/port/config.py new file mode 100644 index 0000000..2364098 --- /dev/null +++ b/WebKitTools/Scripts/webkitpy/layout_tests/port/config.py @@ -0,0 +1,154 @@ +#!/usr/bin/env python +# 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. + +"""Wrapper objects for WebKit-specific utility routines.""" + +# FIXME: This file needs to be unified with common/checkout/scm.py and +# common/config/ports.py . + +from __future__ import with_statement + +import codecs +import os + +from webkitpy.common.checkout import scm +from webkitpy.common.system import logutils + + +_log = logutils.get_logger(__file__) + +# +# This is used to record if we've already hit the filesystem to look +# for a default configuration. We cache this to speed up the unit tests, +# but this can be reset with clear_cached_configuration(). +# +_determined_configuration = None + + +def clear_cached_configuration(): + global _determined_configuration + _determined_configuration = -1 + + +class Config(object): + _FLAGS_FROM_CONFIGURATIONS = { + "Debug": "--debug", + "Release": "--release", + } + + def __init__(self, executive): + self._executive = executive + self._webkit_base_dir = None + self._default_configuration = None + self._build_directories = {} + + def build_directory(self, configuration): + """Returns the path to the build directory for the configuration.""" + if configuration: + flags = ["--configuration", + self._FLAGS_FROM_CONFIGURATIONS[configuration]] + configuration = "" + else: + configuration = "" + flags = ["--top-level"] + + if not self._build_directories.get(configuration): + args = ["perl", self._script_path("webkit-build-directory")] + flags + self._build_directories[configuration] = ( + self._executive.run_command(args).rstrip()) + + return self._build_directories[configuration] + + def build_dumprendertree(self, configuration): + """Builds DRT in the given configuration. + + Returns True if the build was successful and up-to-date.""" + flag = self._FLAGS_FROM_CONFIGURATIONS[configuration] + exit_code = self._executive.run_command([ + self._script_path("build-dumprendertree"), flag], + return_exit_code=True) + if exit_code != 0: + _log.error("Failed to build DumpRenderTree") + return False + return True + + def default_configuration(self): + """Returns the default configuration for the user. + + Returns the value set by 'set-webkit-configuration', or "Release" + if that has not been set. This mirrors the logic in webkitdirs.pm.""" + if not self._default_configuration: + self._default_configuration = self._determine_configuration() + if not self._default_configuration: + self._default_configuration = 'Release' + if self._default_configuration not in self._FLAGS_FROM_CONFIGURATIONS: + _log.warn("Configuration \"%s\" is not a recognized value.\n" % + self._default_configuration) + _log.warn("Scripts may fail. " + "See 'set-webkit-configuration --help'.") + return self._default_configuration + + def path_from_webkit_base(self, *comps): + return os.path.join(self.webkit_base_dir(), *comps) + + def webkit_base_dir(self): + """Returns the absolute path to the top of the WebKit tree. + + Raises an AssertionError if the top dir can't be determined.""" + # FIXME: Consider determining this independently of scm in order + # to be able to run in a bare tree. + if not self._webkit_base_dir: + self._webkit_base_dir = scm.find_checkout_root() + assert self._webkit_base_dir, "Could not determine the top of the WebKit checkout" + return self._webkit_base_dir + + def _script_path(self, script_name): + return os.path.join(self.webkit_base_dir(), "WebKitTools", + "Scripts", script_name) + + def _determine_configuration(self): + # This mirrors the logic in webkitdirs.pm:determineConfiguration(). + global _determined_configuration + if _determined_configuration == -1: + contents = self._read_configuration() + if contents == "Deployment": + contents = "Release" + if contents == "Development": + contents = "Debug" + _determined_configuration = contents + return _determined_configuration + + def _read_configuration(self): + configuration_path = os.path.join(self.build_directory(None), + "Configuration") + if not os.path.exists(configuration_path): + return None + + with codecs.open(configuration_path, "r", "utf-8") as fh: + return fh.read().rstrip() diff --git a/WebKitTools/Scripts/webkitpy/layout_tests/port/config_unittest.py b/WebKitTools/Scripts/webkitpy/layout_tests/port/config_unittest.py new file mode 100644 index 0000000..4674cba --- /dev/null +++ b/WebKitTools/Scripts/webkitpy/layout_tests/port/config_unittest.py @@ -0,0 +1,176 @@ +# 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 codecs +import os +import StringIO +import unittest + +from webkitpy.common.system import outputcapture + +import config + + +# FIXME: This makes StringIO objects work with "with". Remove +# when we upgrade to 2.6. +class NewStringIO(StringIO.StringIO): + def __enter__(self): + return self + + def __exit__(self, type, value, traceback): + pass + + +class MockExecutive(object): + def __init__(self, output='', exit_code=0): + self._output = output + self._exit_code = exit_code + + def run_command(self, arg_list, return_exit_code=False, + decode_output=False): + if return_exit_code: + return self._exit_code + return self._output + + +class ConfigTest(unittest.TestCase): + def tearDown(self): + config.clear_cached_configuration() + + def assertConfiguration(self, contents, expected): + # This tests that a configuration file containing + # _contents_ endsd up being interpreted as _expected_. + # + # FIXME: rewrite this when we have a filesystem abstraction we + # can mock out more easily. + config.clear_cached_configuration() + orig_open = codecs.open + + def wrap_open(contents): + def open_wrapper(path, mode, encoding): + return NewStringIO(contents) + return open_wrapper + + try: + orig_exists = os.path.exists + os.path.exists = lambda p: True + codecs.open = wrap_open(contents) + + e = MockExecutive(output='foo') + c = config.Config(e) + self.assertEqual(c.default_configuration(), expected) + finally: + os.path.exists = orig_exists + codecs.open = orig_open + + def test_build_directory_toplevel(self): + e = MockExecutive(output="toplevel") + c = config.Config(e) + self.assertEqual(c.build_directory(None), 'toplevel') + + # Test again to check caching + self.assertEqual(c.build_directory(None), 'toplevel') + + def test_build_directory__release(self): + e = MockExecutive(output="release") + c = config.Config(e) + self.assertEqual(c.build_directory('Release'), 'release') + + def test_build_directory__debug(self): + e = MockExecutive(output="debug") + c = config.Config(e) + self.assertEqual(c.build_directory('Debug'), 'debug') + + def test_build_directory__unknown(self): + e = MockExecutive(output="unknown") + c = config.Config(e) + self.assertRaises(KeyError, c.build_directory, 'Unknown') + + def test_build_dumprendertree__success(self): + e = MockExecutive(exit_code=0) + c = config.Config(e) + self.assertTrue(c.build_dumprendertree("Debug")) + self.assertTrue(c.build_dumprendertree("Release")) + self.assertRaises(KeyError, c.build_dumprendertree, "Unknown") + + def test_build_dumprendertree__failure(self): + e = MockExecutive(exit_code=-1) + c = config.Config(e) + + oc = outputcapture.OutputCapture() + oc.capture_output() + self.assertFalse(c.build_dumprendertree('Debug')) + (out, err) = oc.restore_output() + + oc.capture_output() + self.assertFalse(c.build_dumprendertree('Release')) + oc.restore_output() + + def test_default_configuration__release(self): + self.assertConfiguration('Release', 'Release') + + def test_default_configuration__debug(self): + self.assertConfiguration('Debug', 'Debug') + + def test_default_configuration__deployment(self): + self.assertConfiguration('Deployment', 'Release') + + def test_default_configuration__development(self): + self.assertConfiguration('Development', 'Debug') + + def test_default_configuration__notfound(self): + # This tests what happens if the default configuration file + # doesn't exist. + config.clear_cached_configuration() + try: + orig_exists = os.path.exists + os.path.exists = lambda p: False + e = MockExecutive(output="foo") + c = config.Config(e) + self.assertEqual(c.default_configuration(), "Release") + finally: + os.path.exists = orig_exists + + def test_default_configuration__unknown(self): + # Ignore the warning about an unknown configuration value. + oc = outputcapture.OutputCapture() + oc.capture_output() + self.assertConfiguration('Unknown', 'Unknown') + oc.restore_output() + + def test_path_from_webkit_base(self, *comps): + c = config.Config(None) + self.assertTrue(c.path_from_webkit_base('foo')) + + def test_webkit_base_dir(self): + c = config.Config(None) + self.assertTrue(c.webkit_base_dir()) + + +if __name__ == '__main__': + unittest.main() diff --git a/WebKitTools/Scripts/webkitpy/layout_tests/port/http_lock.py b/WebKitTools/Scripts/webkitpy/layout_tests/port/http_lock.py index b2615a3..d65801d 100644 --- a/WebKitTools/Scripts/webkitpy/layout_tests/port/http_lock.py +++ b/WebKitTools/Scripts/webkitpy/layout_tests/port/http_lock.py @@ -29,27 +29,38 @@ http and websocket tests in a same time.""" import glob +import logging import os import sys import tempfile import time +from webkitpy.common.system.executive import Executive + + +_log = logging.getLogger("webkitpy.layout_tests.port.http_lock") + class HttpLock(object): def __init__(self, lock_path, lock_file_prefix="WebKitHttpd.lock.", guard_lock="WebKit.lock"): - if not lock_path: + self._lock_path = lock_path + if not self._lock_path: self._lock_path = tempfile.gettempdir() self._lock_file_prefix = lock_file_prefix self._lock_file_path_prefix = os.path.join(self._lock_path, self._lock_file_prefix) self._guard_lock_file = os.path.join(self._lock_path, guard_lock) self._process_lock_file_name = "" + self._executive = Executive() + # maximum wait time for the lock creation + self._guard_lock_max_wait = 1 * 60 def cleanup_http_lock(self): """Delete the lock file if exists.""" if os.path.exists(self._process_lock_file_name): + _log.debug("Removing lock file: %s" % self._process_lock_file_name) os.unlink(self._process_lock_file_name) def _extract_lock_number(self, lock_file_name): @@ -70,17 +81,6 @@ class HttpLock(object): return 0 return self._extract_lock_number(lock_list[-1]) + 1 - def _check_pid(self, current_pid): - """Return True if pid is alive, otherwise return False. - FIXME: os.kill() doesn't work on Windows for checking if - a pid is alive, so always return True""" - if sys.platform in ('darwin', 'linux2'): - try: - os.kill(current_pid, 0) - except OSError: - return False - return True - def _curent_lock_pid(self): """Return with the current lock pid. If the lock is not valid it deletes the lock file.""" @@ -91,7 +91,8 @@ class HttpLock(object): current_lock_file = open(lock_list[0], 'r') current_pid = current_lock_file.readline() current_lock_file.close() - if not (current_pid and self._check_pid(int(current_pid))): + if not (current_pid and self._executive.check_running_pid(int(current_pid))): + _log.debug("Removing stuck lock file: %s" % lock_list[0]) os.unlink(lock_list[0]) return except IOError, OSError: @@ -102,22 +103,34 @@ class HttpLock(object): """The lock files are used to schedule the running test sessions in first come first served order. The sequential guard lock ensures that the lock numbers are sequential.""" + if not os.path.exists(self._lock_path): + _log.debug("Lock directory does not exist: %s" % self._lock_path) + return False + + start_time = time.time() while(True): try: sequential_guard_lock = os.open(self._guard_lock_file, os.O_CREAT | os.O_EXCL) self._process_lock_file_name = (self._lock_file_path_prefix + str(self._next_lock_number())) lock_file = open(self._process_lock_file_name, 'w') + _log.debug("Creating lock file: %s" % self._process_lock_file_name) lock_file.write(str(os.getpid())) lock_file.close() os.close(sequential_guard_lock) os.unlink(self._guard_lock_file) - break + return True except OSError: - pass + if time.time() - start_time > self._guard_lock_max_wait: + _log.debug("Lock does not created: %s" % str(sys.exc_info())) + return False def wait_for_httpd_lock(self): - """Create a lock file and wait until it's turn comes.""" - self._create_lock_file() + """Create a lock file and wait until it's turn comes. If something goes wrong + it wont do any locking.""" + if not self._create_lock_file(): + _log.debug("Warning, http locking failed!") + return + while self._curent_lock_pid() != os.getpid(): time.sleep(1) diff --git a/WebKitTools/Scripts/webkitpy/layout_tests/port/webkit.py b/WebKitTools/Scripts/webkitpy/layout_tests/port/webkit.py index 0d0d3e0..0b324f5 100644 --- a/WebKitTools/Scripts/webkitpy/layout_tests/port/webkit.py +++ b/WebKitTools/Scripts/webkitpy/layout_tests/port/webkit.py @@ -60,7 +60,6 @@ class WebKitPort(base.Port): def __init__(self, **kwargs): base.Port.__init__(self, **kwargs) - self._cached_build_root = None self._cached_apache_path = None # FIXME: disable pixel tests until they are run by default on the @@ -358,12 +357,8 @@ class WebKitPort(base.Port): 'mac-tiger', 'mac-leopard', 'mac-snowleopard') def _build_path(self, *comps): - if not self._cached_build_root: - self._cached_build_root = self._webkit_build_directory([ - "--configuration", - self.flag_from_configuration(self.get_option('configuration')), - ]) - return os.path.join(self._cached_build_root, *comps) + build_root = self._webkit_configuration_build_directory() + return os.path.join(build_root, *comps) def _path_to_driver(self): return self._build_path('DumpRenderTree') diff --git a/WebKitTools/Scripts/webkitpy/layout_tests/rebaseline_chromium_webkit_tests.py b/WebKitTools/Scripts/webkitpy/layout_tests/rebaseline_chromium_webkit_tests.py index 434058e..55c4558 100644 --- a/WebKitTools/Scripts/webkitpy/layout_tests/rebaseline_chromium_webkit_tests.py +++ b/WebKitTools/Scripts/webkitpy/layout_tests/rebaseline_chromium_webkit_tests.py @@ -70,11 +70,11 @@ _log = logging.getLogger("webkitpy.layout_tests." BASELINE_SUFFIXES = ['.txt', '.png', '.checksum'] REBASELINE_PLATFORM_ORDER = ['mac', 'win', 'win-xp', 'win-vista', 'linux'] -ARCHIVE_DIR_NAME_DICT = {'win': 'webkit-rel', +ARCHIVE_DIR_NAME_DICT = {'win': 'Webkit_Win', 'win-vista': 'webkit-dbg-vista', - 'win-xp': 'webkit-rel', - 'mac': 'webkit-rel-mac5', - 'linux': 'webkit-rel-linux', + 'win-xp': 'Webkit_Win', + 'mac': 'Webkit_Mac10_5', + 'linux': 'webkit-rel-linux64', 'win-canary': 'webkit-rel-webkit-org', 'win-vista-canary': 'webkit-dbg-vista', 'win-xp-canary': 'webkit-rel-webkit-org', @@ -819,9 +819,8 @@ def get_host_port_object(options): return port_obj -def main(executive=Executive()): - """Main function to produce new baselines.""" - +def parse_options(args): + """Parse options and return a pair of host options and target options.""" option_parser = optparse.OptionParser() option_parser.add_option('-v', '--verbose', action='store_true', @@ -874,7 +873,20 @@ def main(executive=Executive()): help=('The target platform to rebaseline ' '("mac", "chromium", "qt", etc.). Defaults ' 'to "chromium".')) - options = option_parser.parse_args()[0] + options = option_parser.parse_args(args)[0] + + target_options = copy.copy(options) + if options.target_platform == 'chromium': + target_options.chromium = True + options.tolerance = 0 + + return (options, target_options) + + +def main(executive=Executive()): + """Main function to produce new baselines.""" + + (options, target_options) = parse_options(sys.argv[1:]) # We need to create three different Port objects over the life of this # script. |target_port_obj| is used to determine configuration information: @@ -882,9 +894,6 @@ def main(executive=Executive()): # |port_obj| is used for runtime functionality like actually diffing # Then we create a rebaselining port to actual find and manage the # baselines. - target_options = copy.copy(options) - if options.target_platform == 'chromium': - target_options.chromium = True target_port_obj = port.get(None, target_options) # Set up our logging format. diff --git a/WebKitTools/Scripts/webkitpy/layout_tests/rebaseline_chromium_webkit_tests_unittest.py b/WebKitTools/Scripts/webkitpy/layout_tests/rebaseline_chromium_webkit_tests_unittest.py index 8db31a6..7c55b94 100644 --- a/WebKitTools/Scripts/webkitpy/layout_tests/rebaseline_chromium_webkit_tests_unittest.py +++ b/WebKitTools/Scripts/webkitpy/layout_tests/rebaseline_chromium_webkit_tests_unittest.py @@ -95,6 +95,15 @@ class TestRebaseliner(unittest.TestCase): return rebaseline_chromium_webkit_tests.Rebaseliner( host_port_obj, target_port_obj, platform, options) + def test_parse_options(self): + (options, target_options) = rebaseline_chromium_webkit_tests.parse_options([]) + self.assertTrue(target_options.chromium) + self.assertEqual(options.tolerance, 0) + + (options, target_options) = rebaseline_chromium_webkit_tests.parse_options(['--target-platform', 'qt']) + self.assertFalse(hasattr(target_options, 'chromium')) + self.assertEqual(options.tolerance, 0) + def test_noop(self): # this method tests that was can at least instantiate an object, even # if there is nothing to do. diff --git a/WebKitTools/Scripts/webkitpy/layout_tests/run_webkit_tests.py b/WebKitTools/Scripts/webkitpy/layout_tests/run_webkit_tests.py index 704180c..f360adc 100755 --- a/WebKitTools/Scripts/webkitpy/layout_tests/run_webkit_tests.py +++ b/WebKitTools/Scripts/webkitpy/layout_tests/run_webkit_tests.py @@ -85,6 +85,8 @@ _log = logging.getLogger("webkitpy.layout_tests.run_webkit_tests") # Builder base URL where we have the archived test results. BUILDER_BASE_URL = "http://build.chromium.org/buildbot/layout_test_results/" +LAYOUT_TESTS_DIRECTORY = "LayoutTests" + os.sep + TestExpectationsFile = test_expectations.TestExpectationsFile @@ -283,12 +285,17 @@ class TestRunner: last_unexpected_results: list of unexpected results to retest, if any """ - paths = [arg for arg in args if arg and arg != ''] + paths = [self._strip_test_dir_prefix(arg) for arg in args if arg and arg != ''] paths += last_unexpected_results if self._options.test_list: paths += read_test_files(self._options.test_list) self._test_files = self._port.tests(paths) + def _strip_test_dir_prefix(self, path): + if path.startswith(LAYOUT_TESTS_DIRECTORY): + return path[len(LAYOUT_TESTS_DIRECTORY):] + return path + def lint(self): # Creating the expecations for each platform/configuration pair does # all the test list parsing and ensures it's correct syntax (e.g. no @@ -404,9 +411,8 @@ class TestRunner: # If we reached the end and we don't have enough tests, we run some # from the beginning. - if (self._options.run_chunk and - (slice_end - slice_start < chunk_len)): - extra = 1 + chunk_len - (slice_end - slice_start) + if slice_end - slice_start < chunk_len: + extra = chunk_len - (slice_end - slice_start) extra_msg = (' last chunk is partial, appending [0:%d]' % extra) self._printer.print_expected(extra_msg) @@ -470,9 +476,9 @@ class TestRunner: def _get_dir_for_test_file(self, test_file): """Returns the highest-level directory by which to shard the given test file.""" - index = test_file.rfind(os.sep + 'LayoutTests' + os.sep) + index = test_file.rfind(os.sep + LAYOUT_TESTS_DIRECTORY) - test_file = test_file[index + len('LayoutTests/'):] + test_file = test_file[index + len(LAYOUT_TESTS_DIRECTORY):] test_file_parts = test_file.split(os.sep, 1) directory = test_file_parts[0] test_file = test_file_parts[1] @@ -741,17 +747,6 @@ class TestRunner: if not result_summary: return None - # Do not start when http locking is enabled. - if not self._options.wait_for_httpd: - if self.needs_http(): - self._printer.print_update('Starting HTTP server ...') - self._port.start_http_server() - - if self.needs_websocket(): - self._printer.print_update('Starting WebSocket server ...') - self._port.start_websocket_server() - # self._websocket_secure_server.Start() - return result_summary def run(self, result_summary): @@ -841,11 +836,6 @@ class TestRunner: sys.stdout.flush() _log.debug("flushing stderr") sys.stderr.flush() - if not self._options.wait_for_httpd: - _log.debug("stopping http server") - self._port.stop_http_server() - _log.debug("stopping websocket server") - self._port.stop_websocket_server() _log.debug("stopping helper") self._port.stop_helper() @@ -948,14 +938,15 @@ class TestRunner: if not self._options.test_results_server: return + if not self._options.master_name: + _log.error("--test-results-server was set, but --master-name was not. Not uploading JSON files.") + return + _log.info("Uploading JSON files for builder: %s", self._options.builder_name) - attrs = [("builder", self._options.builder_name), ("testtype", "layout-tests")] - # FIXME: master_name should be required if test_results_server is set. - # Throw an error if master_name isn't set. - if self._options.master_name: - attrs.append(("master", self._options.master_name)) + attrs = [("builder", self._options.builder_name), ("testtype", "layout-tests"), + ("master", self._options.master_name)] json_files = ["expectations.json"] if self._options.upload_full_results: @@ -966,13 +957,6 @@ class TestRunner: files = [(file, os.path.join(self._options.results_directory, file)) for file in json_files] - # FIXME: Remove this. This is temporary debug logging. - if self._options.builder_name.startswith("Webkit Linux"): - for filename in files: - _log.debug(filename[1]) - with codecs.open(filename[1], "r") as results_file: - _log.debug("%s:\n%s" % (filename[0], results_file.read())) - uploader = test_results_uploader.TestResultsUploader( self._options.test_results_server) try: @@ -1530,7 +1514,7 @@ def parse_args(args=None): default=False, help="Don't check the system dependencies (themes)"), optparse.make_option("--use-drt", action="store_true", - default=False, + default=None, help="Use DumpRenderTree instead of test_shell"), optparse.make_option("--accelerated-compositing", action="store_true", @@ -1612,9 +1596,6 @@ def parse_args(args=None): optparse.make_option("--no-record-results", action="store_false", default=True, dest="record_results", help="Don't record the results."), - optparse.make_option("--wait-for-httpd", action="store_true", - default=False, dest="wait_for_httpd", - help="Wait for http locks."), # old-run-webkit-tests also has HTTP toggle options: # --[no-]http Run (or do not run) http tests # (default: run) diff --git a/WebKitTools/Scripts/webkitpy/layout_tests/run_webkit_tests_unittest.py b/WebKitTools/Scripts/webkitpy/layout_tests/run_webkit_tests_unittest.py index 0f09ffa..f21e7a5 100644 --- a/WebKitTools/Scripts/webkitpy/layout_tests/run_webkit_tests_unittest.py +++ b/WebKitTools/Scripts/webkitpy/layout_tests/run_webkit_tests_unittest.py @@ -31,6 +31,7 @@ """Unit tests for run_webkit_tests.""" import codecs +import itertools import logging import os import Queue @@ -48,7 +49,9 @@ from webkitpy.common.system import user 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 +from webkitpy.layout_tests.port.test import TestPort, TestDriver +from webkitpy.python24.versioning import compare_version +from webkitpy.test.skip import skip_if from webkitpy.thirdparty.mock import Mock @@ -61,41 +64,44 @@ class MockUser(): self.url = url -def passing_run(args=[], port_obj=None, record_results=False, +def passing_run(extra_args=None, port_obj=None, record_results=False, tests_included=False): - new_args = ['--print', 'nothing'] - if not '--platform' in args: - new_args.extend(['--platform', 'test']) + extra_args = extra_args or [] + args = ['--print', 'nothing'] + if not '--platform' in extra_args: + args.extend(['--platform', 'test']) if not record_results: - new_args.append('--no-record-results') - new_args.extend(args) + args.append('--no-record-results') + args.extend(extra_args) if not tests_included: # We use the glob to test that globbing works. - new_args.extend(['passes', - 'http/tests', - 'http/tests/websocket/tests', - 'failures/expected/*']) - options, parsed_args = run_webkit_tests.parse_args(new_args) - if port_obj is None: + args.extend(['passes', + 'http/tests', + 'http/tests/websocket/tests', + 'failures/expected/*']) + options, parsed_args = run_webkit_tests.parse_args(args) + if not port_obj: port_obj = port.get(port_name=options.platform, options=options, user=MockUser()) res = run_webkit_tests.run(port_obj, options, parsed_args) return res == 0 -def logging_run(args=[], tests_included=False): - new_args = ['--no-record-results'] - if not '--platform' in args: - new_args.extend(['--platform', 'test']) - new_args.extend(args) +def logging_run(extra_args=None, port_obj=None, tests_included=False): + extra_args = extra_args or [] + args = ['--no-record-results'] + if not '--platform' in extra_args: + args.extend(['--platform', 'test']) + args.extend(extra_args) if not tests_included: - new_args.extend(['passes', - 'http/tests', - 'http/tests/websocket/tests', - 'failures/expected/*']) - options, parsed_args = run_webkit_tests.parse_args(new_args) + args.extend(['passes', + 'http/tests', + 'http/tests/websocket/tests', + 'failures/expected/*']) + options, parsed_args = run_webkit_tests.parse_args(args) user = MockUser() - port_obj = port.get(port_name=options.platform, options=options, user=user) + if not port_obj: + port_obj = port.get(port_name=options.platform, options=options, user=user) buildbot_output = array_stream.ArrayStream() regular_output = array_stream.ArrayStream() res = run_webkit_tests.run(port_obj, options, parsed_args, @@ -104,6 +110,54 @@ def logging_run(args=[], tests_included=False): return (res, buildbot_output, regular_output, user) +def get_tests_run(extra_args=None, tests_included=False, flatten_batches=False): + extra_args = extra_args or [] + args = [ + '--print', 'nothing', + '--platform', 'test', + '--no-record-results', + '--child-processes', '1'] + args.extend(extra_args) + if not tests_included: + # Not including http tests since they get run out of order (that + # behavior has its own test, see test_get_test_file_queue) + args.extend(['passes', 'failures']) + options, parsed_args = run_webkit_tests.parse_args(args) + user = MockUser() + + test_batches = [] + + class RecordingTestDriver(TestDriver): + def __init__(self, port, image_path, options): + TestDriver.__init__(self, port, image_path, options, executive=None) + self._current_test_batch = None + + def poll(self): + # So that we don't create a new driver for every test + return None + + def stop(self): + self._current_test_batch = None + + def run_test(self, uri, timeoutms, image_hash): + if self._current_test_batch is None: + self._current_test_batch = [] + test_batches.append(self._current_test_batch) + self._current_test_batch.append(self._port.uri_to_test_name(uri)) + return TestDriver.run_test(self, uri, timeoutms, image_hash) + + class RecordingTestPort(TestPort): + def create_driver(self, image_path, options): + return RecordingTestDriver(self, image_path, options) + + recording_port = RecordingTestPort(options=options, user=user) + logging_run(extra_args=args, port_obj=recording_port, tests_included=True) + + if flatten_batches: + return list(itertools.chain(*test_batches)) + + return test_batches + class MainTest(unittest.TestCase): def test_accelerated_compositing(self): # This just tests that we recognize the command line args @@ -119,8 +173,9 @@ class MainTest(unittest.TestCase): self.assertTrue(passing_run()) def test_batch_size(self): - # FIXME: verify # of tests run - self.assertTrue(passing_run(['--batch-size', '2'])) + batch_tests_run = get_tests_run(['--batch-size', '2']) + for batch in batch_tests_run: + 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( @@ -194,8 +249,15 @@ class MainTest(unittest.TestCase): self.assertTrue(passing_run(['--randomize-order'])) def test_run_chunk(self): - # FIXME: verify # of tests run - self.assertTrue(passing_run(['--run-chunk', '1:4'])) + # Test that we actually select the right chunk + all_tests_run = get_tests_run(flatten_batches=True) + chunk_tests_run = get_tests_run(['--run-chunk', '1:4'], flatten_batches=True) + self.assertEquals(all_tests_run[4:8], chunk_tests_run) + + # Test that we wrap around if the number of tests is not evenly divisible by the chunk size + tests_to_run = ['passes/error.html', 'passes/image.html', 'passes/platform_image.html', 'passes/text.html'] + chunk_tests_run = get_tests_run(['--run-chunk', '1:3'] + tests_to_run, tests_included=True, flatten_batches=True) + self.assertEquals(['passes/text.html', 'passes/error.html', 'passes/image.html'], chunk_tests_run) def test_run_force(self): # This raises an exception because we run @@ -203,23 +265,33 @@ class MainTest(unittest.TestCase): self.assertRaises(ValueError, logging_run, ['--force']) def test_run_part(self): - # FIXME: verify # of tests run - self.assertTrue(passing_run(['--run-part', '1:2'])) + # Test that we actually select the right part + tests_to_run = ['passes/error.html', 'passes/image.html', 'passes/platform_image.html', 'passes/text.html'] + tests_run = get_tests_run(['--run-part', '1:2'] + tests_to_run, tests_included=True, flatten_batches=True) + self.assertEquals(['passes/error.html', 'passes/image.html'], tests_run) + + # Test that we wrap around if the number of tests is not evenly divisible by the chunk size + # (here we end up with 3 parts, each with 2 tests, and we only have 4 tests total, so the + # last part repeats the first two tests). + chunk_tests_run = get_tests_run(['--run-part', '3:3'] + tests_to_run, tests_included=True, flatten_batches=True) + self.assertEquals(['passes/error.html', 'passes/image.html'], chunk_tests_run) def test_run_singly(self): - self.assertTrue(passing_run(['--run-singly'])) + batch_tests_run = get_tests_run(['--run-singly']) + for batch in batch_tests_run: + self.assertEquals(len(batch), 1, '%s had too many tests' % ', '.join(batch)) def test_single_file(self): - # FIXME: verify # of tests run - self.assertTrue(passing_run(['passes/text.html'], tests_included=True)) + tests_run = get_tests_run(['passes/text.html'], tests_included=True, flatten_batches=True) + self.assertEquals(['passes/text.html'], tests_run) def test_test_list(self): filename = tempfile.mktemp() tmpfile = file(filename, mode='w+') tmpfile.write('passes/text.html') tmpfile.close() - self.assertTrue(passing_run(['--test-list=%s' % filename], - tests_included=True)) + tests_run = get_tests_run(['--test-list=%s' % filename], tests_included=True, flatten_batches=True) + self.assertEquals(['passes/text.html'], tests_run) os.remove(filename) res, out, err, user = logging_run(['--test-list=%s' % filename], tests_included=True) @@ -271,7 +343,7 @@ class MainTest(unittest.TestCase): def get_port_for_run(args): options, parsed_args = run_webkit_tests.parse_args(args) test_port = ImageDiffTestPort(options=options, user=MockUser()) - passing_run(args=args, port_obj=test_port, tests_included=True) + passing_run(args, port_obj=test_port, tests_included=True) return test_port base_args = ['--pixel-tests', 'failures/expected/*'] @@ -287,6 +359,8 @@ class MainTest(unittest.TestCase): test_port = get_port_for_run(base_args) self.assertEqual(None, test_port.tolerance_used_for_diff_image) +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') + def _mocked_open(original_open, file_list): def _wrapper(name, mode, encoding): diff --git a/WebKitTools/Scripts/webkitpy/style/checker.py b/WebKitTools/Scripts/webkitpy/style/checker.py index 11e3e33..fb93eb9 100644 --- a/WebKitTools/Scripts/webkitpy/style/checker.py +++ b/WebKitTools/Scripts/webkitpy/style/checker.py @@ -115,7 +115,13 @@ _PATH_RULES_SPECIFIER = [ # Files in these directories are consumers of the WebKit # API and therefore do not follow the same header including # discipline as WebCore. - (["WebKitTools/WebKitAPITest/", + + ([# TestNetscapePlugIn has no config.h and uses funny names like + # NPP_SetWindow. + "WebKitTools/DumpRenderTree/TestNetscapePlugIn/", + # The API test harnesses have no config.h and use funny macros like + # TEST_CLASS_NAME. + "WebKitTools/WebKitAPITest/", "WebKitTools/TestWebKitAPI/"], ["-build/include", "-readability/naming"]), diff --git a/WebKitTools/Scripts/webkitpy/style/optparser.py b/WebKitTools/Scripts/webkitpy/style/optparser.py index 3ba0fae..f4e9923 100644 --- a/WebKitTools/Scripts/webkitpy/style/optparser.py +++ b/WebKitTools/Scripts/webkitpy/style/optparser.py @@ -145,6 +145,7 @@ class CommandOptionValues(object): def __init__(self, filter_rules=None, git_commit=None, + diff_files=None, is_verbose=False, min_confidence=1, output_format="emacs"): @@ -163,6 +164,7 @@ class CommandOptionValues(object): self.filter_rules = filter_rules self.git_commit = git_commit + self.diff_files = diff_files self.is_verbose = is_verbose self.min_confidence = min_confidence self.output_format = output_format @@ -174,6 +176,8 @@ class CommandOptionValues(object): return False if self.git_commit != other.git_commit: return False + if self.diff_files != other.diff_files: + return False if self.is_verbose != other.is_verbose: return False if self.min_confidence != other.min_confidence: @@ -214,6 +218,8 @@ class ArgumentPrinter(object): flags['filter'] = ",".join(filter_rules) if options.git_commit: flags['git-commit'] = options.git_commit + if options.diff_files: + flags['diff_files'] = options.diff_files flag_string = '' # Alphabetizing lets us unit test this method. @@ -308,6 +314,9 @@ class ArgumentParser(object): parser.add_option("-g", "--git-diff", "--git-commit", metavar="COMMIT", dest="git_commit", help=git_commit_help,) + diff_files_help = "diff the files passed on the command line rather than checking the style of every line" + parser.add_option("--diff-files", action="store_true", dest="diff_files", default=False, help=diff_files_help) + min_confidence_help = ("set the minimum confidence of style errors " "to report. Can be an integer 1-5, with 1 " "displaying all errors. Defaults to %default.") @@ -409,6 +418,7 @@ class ArgumentParser(object): filter_value = options.filter_value git_commit = options.git_commit + diff_files = options.diff_files is_verbose = options.is_verbose min_confidence = options.min_confidence output_format = options.output_format @@ -420,10 +430,6 @@ class ArgumentParser(object): # Validate user-provided values. - if paths and git_commit: - self._parse_error('You cannot provide both paths and a git ' - 'commit at the same time.') - min_confidence = int(min_confidence) if (min_confidence < 1) or (min_confidence > 5): self._parse_error('option --min-confidence: invalid integer: ' @@ -442,6 +448,7 @@ class ArgumentParser(object): options = CommandOptionValues(filter_rules=filter_rules, git_commit=git_commit, + diff_files=diff_files, is_verbose=is_verbose, min_confidence=min_confidence, output_format=output_format) diff --git a/WebKitTools/Scripts/webkitpy/style/optparser_unittest.py b/WebKitTools/Scripts/webkitpy/style/optparser_unittest.py index b7e3eda..a6b64da 100644 --- a/WebKitTools/Scripts/webkitpy/style/optparser_unittest.py +++ b/WebKitTools/Scripts/webkitpy/style/optparser_unittest.py @@ -136,11 +136,6 @@ class ArgumentParserTest(LoggingTestCase): self.assertLog(['ERROR: Invalid filter rule "build": ' 'every rule must start with + or -.\n']) parse(['--filter=+build']) # works - # Pass files and git-commit at the same time. - self.assertRaises(SystemExit, parse, ['--git-commit=committish', - 'file.txt']) - self.assertLog(['ERROR: You cannot provide both paths and ' - 'a git commit at the same time.\n']) def test_parse_default_arguments(self): parse = self._parse @@ -151,6 +146,7 @@ class ArgumentParserTest(LoggingTestCase): self.assertEquals(options.filter_rules, []) self.assertEquals(options.git_commit, None) + self.assertEquals(options.diff_files, False) self.assertEquals(options.is_verbose, False) self.assertEquals(options.min_confidence, 3) self.assertEquals(options.output_format, 'vs7') @@ -171,6 +167,8 @@ class ArgumentParserTest(LoggingTestCase): self.assertEquals(options.git_commit, 'commit') (files, options) = parse(['--verbose']) self.assertEquals(options.is_verbose, True) + (files, options) = parse(['--diff-files', 'file.txt']) + self.assertEquals(options.diff_files, True) # Pass user_rules. (files, options) = parse(['--filter=+build,-whitespace']) diff --git a/WebKitTools/Scripts/webkitpy/style_references.py b/WebKitTools/Scripts/webkitpy/style_references.py index 34f3bff..a21e931 100644 --- a/WebKitTools/Scripts/webkitpy/style_references.py +++ b/WebKitTools/Scripts/webkitpy/style_references.py @@ -69,6 +69,6 @@ class WebKitCheckout(object): """Return the checkout root as an absolute path.""" return self._scm.checkout_root - def create_patch(self, git_commit): - return self._scm.create_patch(git_commit) - + def create_patch(self, git_commit, changed_files=None): + # FIXME: SCM.create_patch should understand how to handle None. + return self._scm.create_patch(git_commit, changed_files=changed_files or []) diff --git a/WebKitTools/Scripts/webkitpy/test/cat.py b/WebKitTools/Scripts/webkitpy/test/cat.py new file mode 100644 index 0000000..ae1e143 --- /dev/null +++ b/WebKitTools/Scripts/webkitpy/test/cat.py @@ -0,0 +1,42 @@ +# 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. + +import os.path +import sys + +# Add WebKitTools/Scripts to the path to ensure we can find webkitpy. +sys.path.append(os.path.dirname(os.path.dirname(os.path.dirname(__file__)))) + +from webkitpy.common.system import fileutils + + +def command_arguments(*args): + return ['python', __file__] + list(args) + + +def main(): + fileutils.make_stdout_binary() + sys.stdout.write(sys.stdin.read()) + return 0 + +if __name__ == '__main__': + sys.exit(main()) diff --git a/WebKitTools/Scripts/webkitpy/test/cat_unittest.py b/WebKitTools/Scripts/webkitpy/test/cat_unittest.py new file mode 100644 index 0000000..4ed1f67 --- /dev/null +++ b/WebKitTools/Scripts/webkitpy/test/cat_unittest.py @@ -0,0 +1,52 @@ +# 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. + +import StringIO +import os.path +import sys +import unittest + +from webkitpy.common.system import executive, outputcapture +from webkitpy.test import cat + + +class CatTest(outputcapture.OutputCaptureTestCaseBase): + def assert_cat(self, input): + saved_stdin = sys.stdin + sys.stdin = StringIO.StringIO(input) + cat.main() + self.assertStdout(input) + sys.stdin = saved_stdin + + def test_basic(self): + self.assert_cat('foo bar baz\n') + + def test_no_newline(self): + self.assert_cat('foo bar baz') + + def test_unicode(self): + self.assert_cat(u'WebKit \u2661 Tor Arne Vestb\u00F8!') + + def test_as_command(self): + input = 'foo bar baz\n' + output = executive.Executive().run_command(cat.command_arguments(), input=input) + self.assertEqual(input, output) diff --git a/WebKitTools/Scripts/webkitpy/test/echo.py b/WebKitTools/Scripts/webkitpy/test/echo.py new file mode 100644 index 0000000..f7468f7 --- /dev/null +++ b/WebKitTools/Scripts/webkitpy/test/echo.py @@ -0,0 +1,52 @@ +# 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. + +import os.path +import sys + +# Add WebKitTools/Scripts to the path to ensure we can find webkitpy. +sys.path.append(os.path.dirname(os.path.dirname(os.path.dirname(__file__)))) + +from webkitpy.common.system import fileutils + + +def command_arguments(*args): + return ['python', __file__] + list(args) + + +def main(args=None): + if args is None: + args = sys.argv[1:] + + fileutils.make_stdout_binary() + + print_newline = True + if len(args) and args[0] == '-n': + print_newline = False + del args[0] + sys.stdout.write(' '.join(args)) + if print_newline: + sys.stdout.write('\n') + return 0 + +if __name__ == '__main__': + sys.exit(main()) diff --git a/WebKitTools/Scripts/webkitpy/test/echo_unittest.py b/WebKitTools/Scripts/webkitpy/test/echo_unittest.py new file mode 100644 index 0000000..bc13b5e --- /dev/null +++ b/WebKitTools/Scripts/webkitpy/test/echo_unittest.py @@ -0,0 +1,64 @@ +# 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. + +import os.path +import sys +import unittest + +from webkitpy.common.system import executive, outputcapture +from webkitpy.test import echo + + +class EchoTest(outputcapture.OutputCaptureTestCaseBase): + def test_basic(self): + echo.main(['foo', 'bar', 'baz']) + self.assertStdout('foo bar baz\n') + + def test_no_newline(self): + echo.main(['-n', 'foo', 'bar', 'baz']) + self.assertStdout('foo bar baz') + + def test_unicode(self): + echo.main([u'WebKit \u2661', 'Tor Arne', u'Vestb\u00F8!']) + self.assertStdout(u'WebKit \u2661 Tor Arne Vestb\u00F8!\n') + + def test_argument_order(self): + echo.main(['foo', '-n', 'bar']) + self.assertStdout('foo -n bar\n') + + def test_empty_arguments(self): + old_argv = sys.argv + sys.argv = ['echo.py', 'foo', 'bar', 'baz'] + echo.main([]) + self.assertStdout('\n') + sys.argv = old_argv + + def test_no_arguments(self): + old_argv = sys.argv + sys.argv = ['echo.py', 'foo', 'bar', 'baz'] + echo.main() + self.assertStdout('foo bar baz\n') + sys.argv = old_argv + + def test_as_command(self): + output = executive.Executive().run_command(echo.command_arguments('foo', 'bar', 'baz')) + self.assertEqual(output, 'foo bar baz\n') diff --git a/WebKitTools/Scripts/webkitpy/test/skip.py b/WebKitTools/Scripts/webkitpy/test/skip.py new file mode 100644 index 0000000..8587d56 --- /dev/null +++ b/WebKitTools/Scripts/webkitpy/test/skip.py @@ -0,0 +1,52 @@ +# 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. + +import logging + +_log = logging.getLogger(__name__) + + +def skip_if(klass, condition, message=None, logger=None): + """Makes all test_* methods in a given class no-ops if the given condition + is False. Backported from Python 3.1+'s unittest.skipIf decorator.""" + if not logger: + logger = _log + if not condition: + return klass + for name in dir(klass): + attr = getattr(klass, name) + if not callable(attr): + continue + if not name.startswith('test_'): + continue + setattr(klass, name, _skipped_method(attr, message, logger)) + klass._printed_skipped_message = False + return klass + + +def _skipped_method(method, message, logger): + def _skip(*args): + if method.im_class._printed_skipped_message: + return + method.im_class._printed_skipped_message = True + logger.info('Skipping %s.%s: %s' % (method.__module__, method.im_class.__name__, message)) + return _skip diff --git a/WebKitTools/Scripts/webkitpy/test/skip_unittest.py b/WebKitTools/Scripts/webkitpy/test/skip_unittest.py new file mode 100644 index 0000000..f61a1bb --- /dev/null +++ b/WebKitTools/Scripts/webkitpy/test/skip_unittest.py @@ -0,0 +1,77 @@ +# 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. + +import StringIO +import logging +import unittest + +from webkitpy.test.skip import skip_if + + +class SkipTest(unittest.TestCase): + def setUp(self): + self.logger = logging.getLogger(__name__) + + self.old_level = self.logger.level + self.logger.setLevel(logging.INFO) + + self.old_propagate = self.logger.propagate + self.logger.propagate = False + + self.log_stream = StringIO.StringIO() + self.handler = logging.StreamHandler(self.log_stream) + self.logger.addHandler(self.handler) + + self.foo_was_called = False + + def tearDown(self): + self.logger.removeHandler(self.handler) + self.propagate = self.old_propagate + self.logger.setLevel(self.old_level) + + def create_fixture_class(self): + class TestSkipFixture(object): + def __init__(self, callback): + self.callback = callback + + def test_foo(self): + self.callback() + + return TestSkipFixture + + def foo_callback(self): + self.foo_was_called = True + + def test_skip_if_false(self): + klass = skip_if(self.create_fixture_class(), False, 'Should not see this message.', logger=self.logger) + klass(self.foo_callback).test_foo() + self.assertEqual(self.log_stream.getvalue(), '') + self.assertTrue(self.foo_was_called) + + def test_skip_if_true(self): + klass = skip_if(self.create_fixture_class(), True, 'Should see this message.', logger=self.logger) + klass(self.foo_callback).test_foo() + self.assertEqual(self.log_stream.getvalue(), 'Skipping webkitpy.test.skip_unittest.TestSkipFixture: Should see this message.\n') + self.assertFalse(self.foo_was_called) + +if __name__ == '__main__': + unittest.main() diff --git a/WebKitTools/Scripts/webkitpy/tool/commands/__init__.py b/WebKitTools/Scripts/webkitpy/tool/commands/__init__.py index 9bdec8f..a070324 100644 --- a/WebKitTools/Scripts/webkitpy/tool/commands/__init__.py +++ b/WebKitTools/Scripts/webkitpy/tool/commands/__init__.py @@ -2,4 +2,5 @@ from webkitpy.tool.commands.prettydiff import PrettyDiff from webkitpy.tool.commands.rebaseline import Rebaseline +from webkitpy.tool.commands.rebaselineserver import RebaselineServer # FIXME: Add the rest of the commands here. diff --git a/WebKitTools/Scripts/webkitpy/tool/commands/data/rebaselineserver/index.html b/WebKitTools/Scripts/webkitpy/tool/commands/data/rebaselineserver/index.html new file mode 100644 index 0000000..5667cd2 --- /dev/null +++ b/WebKitTools/Scripts/webkitpy/tool/commands/data/rebaselineserver/index.html @@ -0,0 +1,40 @@ +<!DOCTYPE html> +<!-- + 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. +--> +<html> +<head> + <title>Layout Test Rebaseline Server</title> + <link rel="stylesheet" href="/main.css" type="text/css"> + <script src="/main.js"></script> +</head> +<body class="loading"> + <a href="/quitquitquit">Exit</a> +</body> +</html> diff --git a/WebKitTools/Scripts/webkitpy/tool/commands/data/rebaselineserver/main.css b/WebKitTools/Scripts/webkitpy/tool/commands/data/rebaselineserver/main.css new file mode 100644 index 0000000..35bd6a5 --- /dev/null +++ b/WebKitTools/Scripts/webkitpy/tool/commands/data/rebaselineserver/main.css @@ -0,0 +1,56 @@ +/* + * 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. + */ + +body { + font-size: 12px; + font-family: Helvetica, Arial, sans-serif; + padding: 0; + margin: 0; +} + +.loading { + opacity: 0.5; +} + +div { + margin: 0; +} + +a, .link { + color: #aaf; + text-decoration: underline; + cursor: pointer; +} + +.link.selected { + color: #fff; + font-weight: bold; + text-decoration: none; +} diff --git a/WebKitTools/Scripts/webkitpy/tool/commands/data/rebaselineserver/main.js b/WebKitTools/Scripts/webkitpy/tool/commands/data/rebaselineserver/main.js new file mode 100644 index 0000000..55f19a4 --- /dev/null +++ b/WebKitTools/Scripts/webkitpy/tool/commands/data/rebaselineserver/main.js @@ -0,0 +1,36 @@ +/* + * 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. + */ + +function main() +{ + document.body.classList.remove('loading'); +} + +window.addEventListener('DOMContentLoaded', main); diff --git a/WebKitTools/Scripts/webkitpy/tool/commands/rebaselineserver.py b/WebKitTools/Scripts/webkitpy/tool/commands/rebaselineserver.py new file mode 100644 index 0000000..0a37677 --- /dev/null +++ b/WebKitTools/Scripts/webkitpy/tool/commands/rebaselineserver.py @@ -0,0 +1,157 @@ +# 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. + +"""Starts a local HTTP server which displays layout test failures (given a test +results directory), provides comparisons of expected and actual results (both +images and text) and allows one-click rebaselining of tests.""" +from __future__ import with_statement + +import codecs +import datetime +import mimetypes +import os +import os.path +import shutil +import threading +import time +import urlparse +import BaseHTTPServer + +from optparse import make_option +from wsgiref.handlers import format_date_time + +from webkitpy.tool.multicommandtool import AbstractDeclarativeCommand + + +class RebaselineHTTPServer(BaseHTTPServer.HTTPServer): + def __init__(self, httpd_port, results_directory): + BaseHTTPServer.HTTPServer.__init__(self, ("", httpd_port), RebaselineHTTPRequestHandler) + self.results_directory = results_directory + + +class RebaselineHTTPRequestHandler(BaseHTTPServer.BaseHTTPRequestHandler): + STATIC_FILE_NAMES = frozenset([ + "index.html", + "main.js", + "main.css", + ]) + + STATIC_FILE_DIRECTORY = os.path.join( + os.path.dirname(__file__), "data", "rebaselineserver") + + def do_GET(self): + self._handle_request() + + def do_POST(self): + self._handle_request() + + def _handle_request(self): + # Parse input. + if "?" in self.path: + path, query_string = self.path.split("?", 1) + self.query = urlparse.parse_qs(query_string) + else: + path = self.path + self.query = {} + function_or_file_name = path[1:] or "index.html" + + # See if a static file matches. + if function_or_file_name in RebaselineHTTPRequestHandler.STATIC_FILE_NAMES: + self._serve_static_file(function_or_file_name) + return + + # See if a class method matches. + function_name = function_or_file_name.replace(".", "_") + if not hasattr(self, function_name): + self.send_error(404, "Unknown function %s" % function_name) + return + if function_name[0] == "_": + self.send_error( + 401, "Not allowed to invoke private or protected methods") + return + function = getattr(self, function_name) + function() + + def _serve_static_file(self, static_path): + self._serve_file(os.path.join( + RebaselineHTTPRequestHandler.STATIC_FILE_DIRECTORY, static_path)) + + def quitquitquit(self): + self.send_response(200) + self.send_header("Content-type", "text/plain") + self.end_headers() + self.wfile.write("Quit.\n") + + # Shutdown has to happen on another thread from the server's thread, + # otherwise there's a deadlock + threading.Thread(target=lambda: self.server.shutdown()).start() + + def _serve_file(self, file_path, cacheable_seconds=0): + if not os.path.exists(file_path): + self.send_error(404, "File not found") + return + with codecs.open(file_path, "rb") as static_file: + self.send_response(200) + self.send_header("Content-Length", os.path.getsize(file_path)) + mime_type, encoding = mimetypes.guess_type(file_path) + if mime_type: + self.send_header("Content-type", mime_type) + + if cacheable_seconds: + expires_time = (datetime.datetime.now() + + datetime.timedelta(0, cacheable_seconds)) + expires_formatted = format_date_time( + time.mktime(expires_time.timetuple())) + self.send_header("Expires", expires_formatted) + self.end_headers() + + shutil.copyfileobj(static_file, self.wfile) + + +class RebaselineServer(AbstractDeclarativeCommand): + name = "rebaseline-server" + help_text = __doc__ + argument_names = "/path/to/results/directory" + + def __init__(self): + options = [ + make_option("--httpd-port", action="store", type="int", default=8127, help="Port to use for the the rebaseline HTTP server"), + ] + AbstractDeclarativeCommand.__init__(self, options=options) + + def execute(self, options, args, tool): + results_directory = args[0] + + print "Starting server at http://localhost:%d/" % options.httpd_port + print ("Use the 'Exit' link in the UI, http://localhost:%d/" + "quitquitquit or Ctrl-C to stop") % options.httpd_port + + httpd = RebaselineHTTPServer( + httpd_port=options.httpd_port, + results_directory=results_directory) + httpd.serve_forever() diff --git a/WebKitTools/Scripts/webkitpy/tool/commands/upload.py b/WebKitTools/Scripts/webkitpy/tool/commands/upload.py index ed91f5a..e12c8e2 100644 --- a/WebKitTools/Scripts/webkitpy/tool/commands/upload.py +++ b/WebKitTools/Scripts/webkitpy/tool/commands/upload.py @@ -92,6 +92,32 @@ class CleanPendingCommit(AbstractDeclarativeCommand): self._tool.bugs.obsolete_attachment(patch.id(), message) +# FIXME: This should be share more logic with AssignToCommitter and CleanPendingCommit +class CleanReviewQueue(AbstractDeclarativeCommand): + name = "clean-review-queue" + help_text = "Clear r? on obsolete patches so they do not appear in the pending-commit list." + + def execute(self, options, args, tool): + queue_url = "http://webkit.org/pending-review" + # We do this inefficient dance to be more like webkit.org/pending-review + # bugs.queries.fetch_bug_ids_from_review_queue() doesn't return + # closed bugs, but folks using /pending-review will see them. :( + for patch_id in tool.bugs.queries.fetch_attachment_ids_from_review_queue(): + patch = self._tool.bugs.fetch_attachment(patch_id) + if not patch.review() == "?": + continue + attachment_obsolete_modifier = "" + if patch.is_obsolete(): + attachment_obsolete_modifier = "obsolete " + elif patch.bug().is_closed(): + bug_closed_explanation = " If you would like this patch reviewed, please attach it to a new bug (or re-open this bug before marking it for review again)." + else: + # Neither the patch was obsolete or the bug was closed, next patch... + continue + message = "Cleared review? from %sattachment %s so that this bug does not appear in %s.%s" % (attachment_obsolete_modifier, patch.id(), queue_url, bug_closed_explanation) + self._tool.bugs.obsolete_attachment(patch.id(), message) + + class AssignToCommitter(AbstractDeclarativeCommand): name = "assign-to-committer" help_text = "Assign bug to whoever attached the most recent r+'d patch" diff --git a/WebKitTools/Scripts/webkitpy/tool/mocktool.py b/WebKitTools/Scripts/webkitpy/tool/mocktool.py index af232d9..b6ee95f 100644 --- a/WebKitTools/Scripts/webkitpy/tool/mocktool.py +++ b/WebKitTools/Scripts/webkitpy/tool/mocktool.py @@ -424,6 +424,9 @@ class MockSCM(Mock): # will actually be the root. Since getcwd() is wrong, use a globally fake root for now. self.checkout_root = self.fake_checkout_root + def changed_files(self, git_commit=None): + return ["MockFile1"] + def create_patch(self, git_commit, changed_files=None): return "Patch1" diff --git a/WebKitTools/Scripts/webkitpy/tool/steps/checkstyle.py b/WebKitTools/Scripts/webkitpy/tool/steps/checkstyle.py index af38214..af66c50 100644 --- a/WebKitTools/Scripts/webkitpy/tool/steps/checkstyle.py +++ b/WebKitTools/Scripts/webkitpy/tool/steps/checkstyle.py @@ -52,6 +52,9 @@ class CheckStyle(AbstractStep): args.append("--git-commit") args.append(self._options.git_commit) + args.append("--diff-files") + args.extend(self._changed_files(state)) + try: self._run_script("check-webkit-style", args) except ScriptError, e: diff --git a/WebKitTools/TestWebKitAPI/InjectedBundleController.cpp b/WebKitTools/TestWebKitAPI/InjectedBundleController.cpp index 2674801..5942ec8 100644 --- a/WebKitTools/TestWebKitAPI/InjectedBundleController.cpp +++ b/WebKitTools/TestWebKitAPI/InjectedBundleController.cpp @@ -45,7 +45,7 @@ InjectedBundleController::InjectedBundleController() { } -void InjectedBundleController::initialize(WKBundleRef bundle) +void InjectedBundleController::initialize(WKBundleRef bundle, WKTypeRef initializationUserData) { m_bundle = bundle; @@ -57,6 +57,12 @@ void InjectedBundleController::initialize(WKBundleRef bundle) didReceiveMessage }; WKBundleSetClient(m_bundle, &client); + + // Initialize the test from the "initializationUserData". + assert(WKGetTypeID(initializationUserData) == WKStringGetTypeID()); + WKStringRef testName = static_cast<WKStringRef>(initializationUserData); + + initializeTestNamed(bundle, Util::toSTD(testName)); } void InjectedBundleController::didCreatePage(WKBundleRef bundle, WKBundlePageRef page, const void* clientInfo) @@ -76,16 +82,6 @@ void InjectedBundleController::willDestroyPage(WKBundleRef bundle, WKBundlePageR void InjectedBundleController::didReceiveMessage(WKBundleRef bundle, WKStringRef messageName, WKTypeRef messageBody, const void* clientInfo) { InjectedBundleController* self = static_cast<InjectedBundleController*>(const_cast<void*>(clientInfo)); - - if (WKStringIsEqualToUTF8CString(messageName, "BundleTestInstantiator")) { - assert(WKGetTypeID(messageBody) == WKStringGetTypeID()); - WKStringRef messageBodyString = static_cast<WKStringRef>(messageBody); - - self->initializeTestNamed(bundle, Util::toSTD(messageBodyString)); - - return; - } - assert(self->m_currentTest); self->m_currentTest->didReceiveMessage(bundle, messageName, messageBody); } diff --git a/WebKitTools/TestWebKitAPI/InjectedBundleController.h b/WebKitTools/TestWebKitAPI/InjectedBundleController.h index 8b45fff..91c571e 100644 --- a/WebKitTools/TestWebKitAPI/InjectedBundleController.h +++ b/WebKitTools/TestWebKitAPI/InjectedBundleController.h @@ -38,7 +38,7 @@ class InjectedBundleController { public: static InjectedBundleController& shared(); - void initialize(WKBundleRef); + void initialize(WKBundleRef, WKTypeRef); void dumpTestNames(); void initializeTestNamed(WKBundleRef bundle, const std::string&); diff --git a/WebKitTools/TestWebKitAPI/InjectedBundleMain.cpp b/WebKitTools/TestWebKitAPI/InjectedBundleMain.cpp index 8f9e8ad..355c35b 100644 --- a/WebKitTools/TestWebKitAPI/InjectedBundleMain.cpp +++ b/WebKitTools/TestWebKitAPI/InjectedBundleMain.cpp @@ -31,7 +31,7 @@ extern "C" __declspec(dllexport) #else extern "C" #endif -void WKBundleInitialize(WKBundleRef bundle) +void WKBundleInitialize(WKBundleRef bundle, WKTypeRef initializationUserData) { - TestWebKitAPI::InjectedBundleController::shared().initialize(bundle); + TestWebKitAPI::InjectedBundleController::shared().initialize(bundle, initializationUserData); } diff --git a/WebKitTools/TestWebKitAPI/PlatformUtilities.cpp b/WebKitTools/TestWebKitAPI/PlatformUtilities.cpp index 2fadf3a..281fb13 100644 --- a/WebKitTools/TestWebKitAPI/PlatformUtilities.cpp +++ b/WebKitTools/TestWebKitAPI/PlatformUtilities.cpp @@ -37,13 +37,10 @@ WKContextRef createContextForInjectedBundleTest(const std::string& testName) { WKRetainPtr<WKStringRef> injectedBundlePath(AdoptWK, createInjectedBundlePath()); WKContextRef context = WKContextCreateWithInjectedBundlePath(injectedBundlePath.get()); - - WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("BundleTestInstantiator")); - WKRetainPtr<WKStringRef> messageBody(AdoptWK, WKStringCreateWithUTF8CString(testName.c_str())); - // Enqueue message to instantiate the bundle test. - WKContextPostMessageToInjectedBundle(context, messageName.get(), messageBody.get()); - + WKRetainPtr<WKStringRef> testNameString(AdoptWK, WKStringCreateWithUTF8CString(testName.c_str())); + WKContextSetInitializationUserDataForInjectedBundle(context, testNameString.get()); + return context; } diff --git a/WebKitTools/TestWebKitAPI/Tests/WebKit2/FailedLoad.cpp b/WebKitTools/TestWebKitAPI/Tests/WebKit2/FailedLoad.cpp index b7db746..0ccee5a 100644 --- a/WebKitTools/TestWebKitAPI/Tests/WebKit2/FailedLoad.cpp +++ b/WebKitTools/TestWebKitAPI/Tests/WebKit2/FailedLoad.cpp @@ -41,10 +41,7 @@ static void didFailProvisionalLoadWithErrorForFrame(WKPageRef page, WKFrameRef f TEST_ASSERT(WKFrameGetFrameLoadState(frame) == kWKFrameLoadStateFinished); WKURLRef url = WKFrameCopyProvisionalURL(frame); - WKURLRef emptyURL = WKURLCreateWithUTF8CString(""); - TEST_ASSERT(WKURLIsEqual(url, emptyURL)); - WKRelease(url); - WKRelease(emptyURL); + TEST_ASSERT(!url); testDone = true; } diff --git a/WebKitTools/WebKitLauncher/WebKitLauncher.xcodeproj/project.pbxproj b/WebKitTools/WebKitLauncher/WebKitLauncher.xcodeproj/project.pbxproj index 36eacc5..c130f45 100644 --- a/WebKitTools/WebKitLauncher/WebKitLauncher.xcodeproj/project.pbxproj +++ b/WebKitTools/WebKitLauncher/WebKitLauncher.xcodeproj/project.pbxproj @@ -239,7 +239,14 @@ isa = PBXProject; buildConfigurationList = C01FCF4E08A954540054247B /* Build configuration list for PBXProject "WebKitLauncher" */; compatibilityVersion = "Xcode 3.1"; + developmentRegion = English; hasScannedForEncodings = 1; + knownRegions = ( + English, + Japanese, + French, + German, + ); mainGroup = 29B97314FDCFA39411CA2CEA /* WebKit */; projectDirPath = ""; projectRoot = ""; diff --git a/WebKitTools/WebKitTestRunner/InjectedBundle/Bindings/LayoutTestController.idl b/WebKitTools/WebKitTestRunner/InjectedBundle/Bindings/LayoutTestController.idl index a0e36ad..583eb0a 100644 --- a/WebKitTools/WebKitTestRunner/InjectedBundle/Bindings/LayoutTestController.idl +++ b/WebKitTools/WebKitTestRunner/InjectedBundle/Bindings/LayoutTestController.idl @@ -64,6 +64,8 @@ module WTR { // Animation testing. int numberOfActiveAnimations(); boolean pauseAnimationAtTimeOnElementWithId(in DOMString animationName, in double time, in DOMString elementId); + void suspendAnimations(); + void resumeAnimations(); // UserContent testing. void addUserScript(in DOMString source, in boolean runAtStart, in boolean allFrames); diff --git a/WebKitTools/WebKitTestRunner/InjectedBundle/InjectedBundleMain.cpp b/WebKitTools/WebKitTestRunner/InjectedBundle/InjectedBundleMain.cpp index b1bc89d..c4cf892 100644 --- a/WebKitTools/WebKitTestRunner/InjectedBundle/InjectedBundleMain.cpp +++ b/WebKitTools/WebKitTestRunner/InjectedBundle/InjectedBundleMain.cpp @@ -31,7 +31,7 @@ extern "C" __declspec(dllexport) #else extern "C" #endif -void WKBundleInitialize(WKBundleRef bundle) +void WKBundleInitialize(WKBundleRef bundle, WKTypeRef initializationUserData) { WTR::InjectedBundle::shared().initialize(bundle); } diff --git a/WebKitTools/WebKitTestRunner/InjectedBundle/LayoutTestController.cpp b/WebKitTools/WebKitTestRunner/InjectedBundle/LayoutTestController.cpp index e828c46..de37383 100644 --- a/WebKitTools/WebKitTestRunner/InjectedBundle/LayoutTestController.cpp +++ b/WebKitTools/WebKitTestRunner/InjectedBundle/LayoutTestController.cpp @@ -150,6 +150,18 @@ bool LayoutTestController::pauseAnimationAtTimeOnElementWithId(JSStringRef anima return WKBundleFramePauseAnimationOnElementWithId(mainFrame, toWK(animationName).get(), toWK(elementId).get(), time); } +void LayoutTestController::suspendAnimations() +{ + WKBundleFrameRef mainFrame = WKBundlePageGetMainFrame(InjectedBundle::shared().page()->page()); + WKBundleFrameSuspendAnimations(mainFrame); +} + +void LayoutTestController::resumeAnimations() +{ + WKBundleFrameRef mainFrame = WKBundlePageGetMainFrame(InjectedBundle::shared().page()->page()); + WKBundleFrameResumeAnimations(mainFrame); +} + JSRetainPtr<JSStringRef> LayoutTestController::layerTreeAsText() const { WKBundleFrameRef mainFrame = WKBundlePageGetMainFrame(InjectedBundle::shared().page()->page()); diff --git a/WebKitTools/WebKitTestRunner/InjectedBundle/LayoutTestController.h b/WebKitTools/WebKitTestRunner/InjectedBundle/LayoutTestController.h index dfafb55..427d05e 100644 --- a/WebKitTools/WebKitTestRunner/InjectedBundle/LayoutTestController.h +++ b/WebKitTools/WebKitTestRunner/InjectedBundle/LayoutTestController.h @@ -91,7 +91,9 @@ public: // Animation testing. unsigned numberOfActiveAnimations() const; bool pauseAnimationAtTimeOnElementWithId(JSStringRef animationName, double time, JSStringRef elementId); - + void suspendAnimations(); + void resumeAnimations(); + // Compositing testing. JSRetainPtr<JSStringRef> layerTreeAsText() const; diff --git a/WebKitTools/WebKitTestRunner/TestController.cpp b/WebKitTools/WebKitTestRunner/TestController.cpp index c88062a..8ca0529 100644 --- a/WebKitTools/WebKitTestRunner/TestController.cpp +++ b/WebKitTools/WebKitTestRunner/TestController.cpp @@ -35,6 +35,9 @@ namespace WTR { +static const double defaultLongTimeout = 30; +static const double defaultShortTimeout = 5; + static WKURLRef blankURL() { static WKURLRef staticBlankURL = WKURLCreateWithUTF8CString("about:blank"); @@ -56,6 +59,8 @@ TestController::TestController(int argc, const char* argv[]) , m_usingServerMode(false) , m_state(Initial) , m_doneResetting(false) + , m_longTimeout(defaultLongTimeout) + , m_shortTimeout(defaultShortTimeout) { initialize(argc, argv); controller = this; @@ -146,6 +151,12 @@ void TestController::initialize(int argc, const char* argv[]) for (int i = 1; i < argc; ++i) { std::string argument(argv[i]); + if (argument == "--timeout" && i + 1 < argc) { + m_longTimeout = atoi(argv[++i]); + // Scale up the short timeout to match. + m_shortTimeout = defaultShortTimeout * m_longTimeout / defaultLongTimeout; + continue; + } if (argument == "--pixel-tests") { m_dumpPixels = true; continue; @@ -253,7 +264,7 @@ void TestController::initialize(int argc, const char* argv[]) WKPageSetPageLoaderClient(m_mainWebView->page(), &pageLoaderClient); } -void TestController::resetStateToConsistentValues() +bool TestController::resetStateToConsistentValues() { m_state = Resetting; @@ -285,17 +296,21 @@ void TestController::resetStateToConsistentValues() m_doneResetting = false; WKPageLoadURL(m_mainWebView->page(), blankURL()); - TestController::runUntil(m_doneResetting); + runUntil(m_doneResetting, ShortTimeout); + return m_doneResetting; } -void TestController::runTest(const char* test) +bool TestController::runTest(const char* test) { - resetStateToConsistentValues(); + if (!resetStateToConsistentValues()) + return false; m_state = RunningTest; m_currentInvocation.set(new TestInvocation(test)); m_currentInvocation->invoke(); m_currentInvocation.clear(); + + return true; } void TestController::runTestingServerLoop() @@ -309,7 +324,8 @@ void TestController::runTestingServerLoop() if (strlen(filenameBuffer) == 0) continue; - runTest(filenameBuffer); + if (!runTest(filenameBuffer)) + break; } } @@ -318,11 +334,18 @@ void TestController::run() if (m_usingServerMode) runTestingServerLoop(); else { - for (size_t i = 0; i < m_paths.size(); ++i) - runTest(m_paths[i].c_str()); + for (size_t i = 0; i < m_paths.size(); ++i) { + if (!runTest(m_paths[i].c_str())) + break; + } } } +void TestController::runUntil(bool& done, TimeoutDuration timeoutDuration) +{ + platformRunUntil(done, timeoutDuration == ShortTimeout ? m_shortTimeout : m_longTimeout); +} + // WKContextInjectedBundleClient void TestController::didReceiveMessageFromInjectedBundle(WKContextRef context, WKStringRef messageName, WKTypeRef messageBody, const void* clientInfo) diff --git a/WebKitTools/WebKitTestRunner/TestController.h b/WebKitTools/WebKitTestRunner/TestController.h index b12f1b2..1396c94 100644 --- a/WebKitTools/WebKitTestRunner/TestController.h +++ b/WebKitTools/WebKitTestRunner/TestController.h @@ -53,22 +53,24 @@ public: WKPageNamespaceRef pageNamespace() { return m_pageNamespace.get(); } WKContextRef context() { return m_context.get(); } - // Helper - static void runUntil(bool& done); + // Runs the run loop until `done` is true or the timeout elapses. + enum TimeoutDuration { ShortTimeout, LongTimeout }; + void runUntil(bool& done, TimeoutDuration); private: void initialize(int argc, const char* argv[]); void run(); void runTestingServerLoop(); - void runTest(const char* pathOrURL); + bool runTest(const char* pathOrURL); void platformInitialize(); void platformInitializeContext(); + void platformRunUntil(bool& done, double timeout); void initializeInjectedBundlePath(); void initializeTestPluginDirectory(); - void resetStateToConsistentValues(); + bool resetStateToConsistentValues(); // WKContextInjectedBundleClient static void didReceiveMessageFromInjectedBundle(WKContextRef, WKStringRef messageName, WKTypeRef messageBody, const void*); @@ -102,6 +104,9 @@ private: }; State m_state; bool m_doneResetting; + + double m_longTimeout; + double m_shortTimeout; }; } // namespace WTR diff --git a/WebKitTools/WebKitTestRunner/TestInvocation.cpp b/WebKitTools/WebKitTestRunner/TestInvocation.cpp index 04a56f1..e88de53 100644 --- a/WebKitTools/WebKitTestRunner/TestInvocation.cpp +++ b/WebKitTools/WebKitTestRunner/TestInvocation.cpp @@ -120,7 +120,11 @@ void TestInvocation::invoke() WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("BeginTest")); WKContextPostMessageToInjectedBundle(TestController::shared().context(), messageName.get(), 0); - TestController::runUntil(m_gotInitialResponse); + TestController::shared().runUntil(m_gotInitialResponse, TestController::ShortTimeout); + if (!m_gotInitialResponse) { + dump("Timed out waiting for initial response from web process\n"); + return; + } if (m_error) { dump("FAIL\n"); return; @@ -128,7 +132,11 @@ void TestInvocation::invoke() WKPageLoadURL(TestController::shared().mainWebView()->page(), m_url.get()); - TestController::runUntil(m_gotFinalMessage); + TestController::shared().runUntil(m_gotFinalMessage, TestController::LongTimeout); + if (!m_gotFinalMessage) { + dump("Timed out waiting for final message from web process\n"); + return; + } if (m_error) { dump("FAIL\n"); return; diff --git a/WebKitTools/WebKitTestRunner/mac/TestControllerMac.mm b/WebKitTools/WebKitTestRunner/mac/TestControllerMac.mm index be9aa33..268f718 100644 --- a/WebKitTools/WebKitTestRunner/mac/TestControllerMac.mm +++ b/WebKitTools/WebKitTestRunner/mac/TestControllerMac.mm @@ -45,10 +45,11 @@ void TestController::initializeTestPluginDirectory() m_testPluginDirectory.adopt(WKStringCreateWithCFString((CFStringRef)[[NSBundle mainBundle] bundlePath])); } -void TestController::runUntil(bool& done) +void TestController::platformRunUntil(bool& done, double timeout) { - while (!done) - [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]]; + CFAbsoluteTime end = CFAbsoluteTimeGetCurrent() + timeout; + while (!done && CFAbsoluteTimeGetCurrent() < end) + [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantPast]]; } void TestController::platformInitializeContext() diff --git a/WebKitTools/WebKitTestRunner/qt/TestControllerQt.cpp b/WebKitTools/WebKitTestRunner/qt/TestControllerQt.cpp index d3aee4a..d4de1ba 100644 --- a/WebKitTools/WebKitTestRunner/qt/TestControllerQt.cpp +++ b/WebKitTools/WebKitTestRunner/qt/TestControllerQt.cpp @@ -83,8 +83,9 @@ void TestController::platformInitialize() { } -void TestController::runUntil(bool& done) +void TestController::platformRunUntil(bool& done, double) { + // FIXME: Honor the timeout parameter <http://webkit.org/b/48941>. RunUntilConditionLoop::start(done); ASSERT(done); } @@ -93,7 +94,7 @@ static bool isExistingLibrary(const QString& path) { #if OS(WINDOWS) || OS(SYMBIAN) const char* librarySuffixes[] = { ".dll" }; -#elif PLATFORM(MAC) +#elif OS(MAC_OS_X) const char* librarySuffixes[] = { ".bundle", ".dylib", ".so" }; #elif OS(UNIX) const char* librarySuffixes[] = { ".so" }; diff --git a/WebKitTools/WebKitTestRunner/win/TestControllerWin.cpp b/WebKitTools/WebKitTestRunner/win/TestControllerWin.cpp index 9643c40..3fd853f 100644 --- a/WebKitTools/WebKitTestRunner/win/TestControllerWin.cpp +++ b/WebKitTools/WebKitTestRunner/win/TestControllerWin.cpp @@ -120,15 +120,25 @@ void TestController::initializeTestPluginDirectory() m_testPluginDirectory.adopt(WKStringCreateWithCFString(testPluginDirectoryPath.get())); } -void TestController::runUntil(bool& done) +void TestController::platformRunUntil(bool& done, double timeout) { + DWORD end = ::GetTickCount() + timeout * 1000; while (!done) { - MSG msg; - BOOL result = GetMessage(&msg, 0, 0, 0); - if (result == -1) + DWORD now = ::GetTickCount(); + if (now > end) + return; + + DWORD result = ::MsgWaitForMultipleObjectsEx(0, 0, end - now, QS_ALLINPUT, 0); + if (result == WAIT_TIMEOUT) return; - TranslateMessage(&msg); - DispatchMessage(&msg); + + ASSERT(result == WAIT_OBJECT_0); + // There are messages in the queue. Process them. + MSG msg; + while (::PeekMessageW(&msg, 0, 0, 0, PM_REMOVE)) { + ::TranslateMessage(&msg); + ::DispatchMessageW(&msg); + } } } diff --git a/WebKitTools/iExploder/htdocs/cssproperties.in b/WebKitTools/iExploder/htdocs/cssproperties.in index 9ced1c3..d49eb8e 100644 --- a/WebKitTools/iExploder/htdocs/cssproperties.in +++ b/WebKitTools/iExploder/htdocs/cssproperties.in @@ -37,7 +37,6 @@ -webkit-box-pack -webkit-box-reflect -webkit-box-shadow --webkit-box-sizing -webkit-color-correction -webkit-column-break-after -webkit-column-break-before @@ -156,6 +155,7 @@ border-top-style border-top-width border-width bottom +box-sizing caption-side clear clip |