summaryrefslogtreecommitdiffstats
path: root/Tools
diff options
context:
space:
mode:
authorSteve Block <steveblock@google.com>2011-05-18 13:36:51 +0100
committerSteve Block <steveblock@google.com>2011-05-24 15:38:28 +0100
commit2fc2651226baac27029e38c9d6ef883fa32084db (patch)
treee396d4bf89dcce6ed02071be66212495b1df1dec /Tools
parentb3725cedeb43722b3b175aaeff70552e562d2c94 (diff)
downloadexternal_webkit-2fc2651226baac27029e38c9d6ef883fa32084db.zip
external_webkit-2fc2651226baac27029e38c9d6ef883fa32084db.tar.gz
external_webkit-2fc2651226baac27029e38c9d6ef883fa32084db.tar.bz2
Merge WebKit at r78450: Initial merge by git.
Change-Id: I6d3e5f1f868ec266a0aafdef66182ddc3f265dc1
Diffstat (limited to 'Tools')
-rw-r--r--Tools/BuildSlaveSupport/build.webkit.org-config/config.json16
-rw-r--r--Tools/BuildSlaveSupport/build.webkit.org-config/master.cfg9
-rw-r--r--Tools/BuildSlaveSupport/built-product-archive2
-rw-r--r--Tools/BuildSlaveSupport/test-result-archive2
-rw-r--r--Tools/CMakeListsWinCE.txt1
-rw-r--r--Tools/ChangeLog2689
-rw-r--r--Tools/DerivedSources.pro16
-rw-r--r--Tools/DumpRenderTree/AccessibilityController.cpp9
-rw-r--r--Tools/DumpRenderTree/AccessibilityController.h1
-rw-r--r--Tools/DumpRenderTree/DumpRenderTree.gypi4
-rw-r--r--Tools/DumpRenderTree/LayoutTestController.cpp12
-rw-r--r--Tools/DumpRenderTree/LayoutTestController.h1
-rw-r--r--Tools/DumpRenderTree/TestNetscapePlugIn/PluginObject.cpp20
-rw-r--r--Tools/DumpRenderTree/TestNetscapePlugIn/PluginTest.cpp5
-rw-r--r--Tools/DumpRenderTree/TestNetscapePlugIn/main.cpp32
-rw-r--r--Tools/DumpRenderTree/chromium/DumpRenderTree.cpp8
-rw-r--r--Tools/DumpRenderTree/chromium/ImageDiff.cpp2
-rw-r--r--Tools/DumpRenderTree/chromium/LayoutTestController.cpp26
-rw-r--r--Tools/DumpRenderTree/chromium/LayoutTestController.h4
-rw-r--r--Tools/DumpRenderTree/chromium/NotificationPresenter.cpp2
-rw-r--r--Tools/DumpRenderTree/chromium/TestShell.cpp1
-rw-r--r--Tools/DumpRenderTree/chromium/WebViewHost.cpp41
-rw-r--r--Tools/DumpRenderTree/chromium/WebViewHost.h9
-rw-r--r--Tools/DumpRenderTree/gtk/AccessibilityCallbacks.cpp196
-rw-r--r--Tools/DumpRenderTree/gtk/AccessibilityCallbacks.h35
-rw-r--r--Tools/DumpRenderTree/gtk/AccessibilityControllerGtk.cpp18
-rw-r--r--Tools/DumpRenderTree/gtk/DumpRenderTree.cpp19
-rw-r--r--Tools/DumpRenderTree/gtk/EventSender.cpp47
-rw-r--r--Tools/DumpRenderTree/gtk/LayoutTestControllerGtk.cpp64
-rw-r--r--Tools/DumpRenderTree/gtk/PixelDumpSupportGtk.cpp9
-rw-r--r--Tools/DumpRenderTree/gtk/TextInputController.cpp177
-rw-r--r--Tools/DumpRenderTree/gtk/TextInputController.h37
-rw-r--r--Tools/DumpRenderTree/mac/AccessibilityControllerMac.mm4
-rw-r--r--Tools/DumpRenderTree/mac/DumpRenderTree.mm6
-rw-r--r--Tools/DumpRenderTree/pthreads/JavaScriptThreadingPthreads.cpp62
-rw-r--r--Tools/DumpRenderTree/qt/DumpRenderTree.pro4
-rw-r--r--Tools/DumpRenderTree/qt/DumpRenderTreeQt.cpp40
-rw-r--r--Tools/DumpRenderTree/qt/DumpRenderTreeQt.h2
-rw-r--r--Tools/DumpRenderTree/qt/EventSenderQt.cpp3
-rw-r--r--Tools/DumpRenderTree/qt/EventSenderQt.h2
-rw-r--r--Tools/DumpRenderTree/qt/ImageDiff.pro2
-rw-r--r--Tools/DumpRenderTree/qt/LayoutTestControllerQt.cpp6
-rw-r--r--Tools/DumpRenderTree/qt/LayoutTestControllerQt.h2
-rw-r--r--Tools/DumpRenderTree/qt/TestNetscapePlugin/TestNetscapePlugin.pro2
-rw-r--r--Tools/DumpRenderTree/unix/TestNetscapePlugin/TestNetscapePlugin.cpp3
-rw-r--r--Tools/DumpRenderTree/win/AccessibilityControllerWin.cpp4
-rw-r--r--Tools/DumpRenderTree/win/ImageDiffCommon.vsprops1
-rw-r--r--Tools/DumpRenderTree/wx/LayoutTestControllerWx.cpp5
-rw-r--r--Tools/GNUmakefile.am4
-rw-r--r--Tools/MiniBrowser/DerivedSources.pro7
-rw-r--r--Tools/MiniBrowser/mac/BrowserWindowController.m9
-rw-r--r--Tools/MiniBrowser/mac/WebBundle/WebBundleMain.m2
-rw-r--r--Tools/MiniBrowser/qt/BrowserView.cpp5
-rw-r--r--Tools/MiniBrowser/qt/BrowserView.h1
-rw-r--r--Tools/MiniBrowser/qt/BrowserWindow.cpp259
-rw-r--r--Tools/MiniBrowser/qt/BrowserWindow.h34
-rw-r--r--Tools/MiniBrowser/qt/MiniBrowser.pro14
-rw-r--r--Tools/MiniBrowser/qt/MiniBrowserApplication.cpp95
-rw-r--r--Tools/MiniBrowser/qt/MiniBrowserApplication.h68
-rw-r--r--Tools/MiniBrowser/qt/UrlLoader.cpp129
-rw-r--r--Tools/MiniBrowser/qt/UrlLoader.h71
-rw-r--r--Tools/MiniBrowser/qt/main.cpp44
-rw-r--r--Tools/MiniBrowser/qt/utils.cpp86
-rw-r--r--Tools/MiniBrowser/qt/utils.h53
-rw-r--r--Tools/QtTestBrowser/QtTestBrowser.pro2
-rw-r--r--Tools/QtTestBrowser/launcherwindow.cpp82
-rw-r--r--Tools/QtTestBrowser/launcherwindow.h16
-rw-r--r--Tools/QtTestBrowser/locationedit.h2
-rw-r--r--Tools/QtTestBrowser/main.cpp10
-rw-r--r--Tools/QtTestBrowser/mainwindow.cpp8
-rw-r--r--Tools/QtTestBrowser/mainwindow.h3
-rw-r--r--Tools/QueueStatusServer/templates/submittoews.html2
-rwxr-xr-xTools/Scripts/build-webkit14
-rwxr-xr-xTools/Scripts/check-inspector-strings12
-rwxr-xr-xTools/Scripts/do-webcore-rename2
-rwxr-xr-xTools/Scripts/old-run-webkit-tests170
-rwxr-xr-xTools/Scripts/rebaseline-chromium-webkit-tests2
-rwxr-xr-xTools/Scripts/run-chromium-webkit-unit-tests4
-rwxr-xr-xTools/Scripts/run-webkit-httpd12
-rwxr-xr-xTools/Scripts/update-webkit11
-rwxr-xr-xTools/Scripts/webkit-patch7
-rw-r--r--Tools/Scripts/webkitdirs.pm79
-rw-r--r--Tools/Scripts/webkitperl/httpd.pm25
-rw-r--r--Tools/Scripts/webkitpy/common/checkout/api.py4
-rw-r--r--Tools/Scripts/webkitpy/common/checkout/changelog.py21
-rw-r--r--Tools/Scripts/webkitpy/common/checkout/changelog_unittest.py86
-rw-r--r--Tools/Scripts/webkitpy/common/checkout/deps.py61
-rw-r--r--Tools/Scripts/webkitpy/common/checkout/scm.py24
-rw-r--r--Tools/Scripts/webkitpy/common/checkout/scm_unittest.py11
-rw-r--r--Tools/Scripts/webkitpy/common/config/committers.py8
-rw-r--r--Tools/Scripts/webkitpy/common/config/urls.py1
-rw-r--r--Tools/Scripts/webkitpy/common/net/buildbot/buildbot.py5
-rw-r--r--Tools/Scripts/webkitpy/common/net/buildbot/buildbot_unittest.py6
-rw-r--r--Tools/Scripts/webkitpy/common/net/irc/ircbot.py2
-rw-r--r--Tools/Scripts/webkitpy/common/net/layouttestresults.py4
-rw-r--r--Tools/Scripts/webkitpy/common/net/testoutput.py179
-rw-r--r--Tools/Scripts/webkitpy/common/net/testoutput_unittest.py133
-rw-r--r--Tools/Scripts/webkitpy/common/net/testoutputset.py130
-rw-r--r--Tools/Scripts/webkitpy/common/net/testoutputset_unittest.py125
-rw-r--r--Tools/Scripts/webkitpy/common/system/directoryfileset.py14
-rw-r--r--Tools/Scripts/webkitpy/common/system/fileset.py6
-rw-r--r--Tools/Scripts/webkitpy/common/system/filesystem.py16
-rw-r--r--Tools/Scripts/webkitpy/common/system/filesystem_mock.py71
-rw-r--r--Tools/Scripts/webkitpy/common/system/filesystem_unittest.py13
-rw-r--r--Tools/Scripts/webkitpy/common/system/logutils.py2
-rw-r--r--Tools/Scripts/webkitpy/common/system/logutils_unittest.py2
-rw-r--r--Tools/Scripts/webkitpy/common/system/ospath.py8
-rw-r--r--Tools/Scripts/webkitpy/common/system/stack_utils.py67
-rw-r--r--Tools/Scripts/webkitpy/common/system/stack_utils_unittest.py76
-rw-r--r--Tools/Scripts/webkitpy/common/system/urlfetcher.py (renamed from Tools/Scripts/webkitpy/layout_tests/layout_package/test_output.py)47
-rw-r--r--Tools/Scripts/webkitpy/common/system/urlfetcher_mock.py46
-rw-r--r--Tools/Scripts/webkitpy/common/system/zip_mock.py55
-rw-r--r--Tools/Scripts/webkitpy/common/system/zipfileset.py10
-rw-r--r--Tools/Scripts/webkitpy/common/system/zipfileset_mock.py51
-rw-r--r--Tools/Scripts/webkitpy/common/system/zipfileset_unittest.py6
-rw-r--r--Tools/Scripts/webkitpy/layout_tests/deduplicate_tests.py11
-rw-r--r--Tools/Scripts/webkitpy/layout_tests/layout_package/dump_render_tree_thread.py422
-rw-r--r--Tools/Scripts/webkitpy/layout_tests/layout_package/json_layout_results_generator.py6
-rw-r--r--Tools/Scripts/webkitpy/layout_tests/layout_package/json_results_generator.py113
-rw-r--r--Tools/Scripts/webkitpy/layout_tests/layout_package/json_results_generator_unittest.py29
-rw-r--r--Tools/Scripts/webkitpy/layout_tests/layout_package/manager_worker_broker.py282
-rw-r--r--Tools/Scripts/webkitpy/layout_tests/layout_package/manager_worker_broker_unittest.py227
-rw-r--r--Tools/Scripts/webkitpy/layout_tests/layout_package/message_broker.py41
-rw-r--r--Tools/Scripts/webkitpy/layout_tests/layout_package/message_broker2.py196
-rw-r--r--Tools/Scripts/webkitpy/layout_tests/layout_package/message_broker2_unittest.py83
-rw-r--r--Tools/Scripts/webkitpy/layout_tests/layout_package/message_broker_unittest.py54
-rw-r--r--Tools/Scripts/webkitpy/layout_tests/layout_package/printing_unittest.py8
-rw-r--r--Tools/Scripts/webkitpy/layout_tests/layout_package/single_test_runner.py322
-rw-r--r--Tools/Scripts/webkitpy/layout_tests/layout_package/test_expectations.py554
-rw-r--r--Tools/Scripts/webkitpy/layout_tests/layout_package/test_expectations_unittest.py293
-rw-r--r--Tools/Scripts/webkitpy/layout_tests/layout_package/test_input.py4
-rw-r--r--Tools/Scripts/webkitpy/layout_tests/layout_package/test_runner.py107
-rw-r--r--Tools/Scripts/webkitpy/layout_tests/layout_package/test_runner2.py129
-rw-r--r--Tools/Scripts/webkitpy/layout_tests/layout_package/worker.py104
-rw-r--r--Tools/Scripts/webkitpy/layout_tests/port/base.py175
-rw-r--r--Tools/Scripts/webkitpy/layout_tests/port/base_unittest.py14
-rw-r--r--Tools/Scripts/webkitpy/layout_tests/port/chromium.py74
-rw-r--r--Tools/Scripts/webkitpy/layout_tests/port/chromium_gpu.py119
-rw-r--r--Tools/Scripts/webkitpy/layout_tests/port/chromium_gpu_unittest.py43
-rw-r--r--Tools/Scripts/webkitpy/layout_tests/port/chromium_linux.py4
-rw-r--r--Tools/Scripts/webkitpy/layout_tests/port/chromium_mac.py24
-rw-r--r--Tools/Scripts/webkitpy/layout_tests/port/chromium_unittest.py7
-rw-r--r--Tools/Scripts/webkitpy/layout_tests/port/chromium_win.py10
-rw-r--r--Tools/Scripts/webkitpy/layout_tests/port/dryrun.py22
-rw-r--r--Tools/Scripts/webkitpy/layout_tests/port/factory.py5
-rw-r--r--Tools/Scripts/webkitpy/layout_tests/port/http_server_base.py2
-rw-r--r--Tools/Scripts/webkitpy/layout_tests/port/mac.py6
-rw-r--r--Tools/Scripts/webkitpy/layout_tests/port/mac_unittest.py23
-rw-r--r--Tools/Scripts/webkitpy/layout_tests/port/mock_drt.py280
-rw-r--r--Tools/Scripts/webkitpy/layout_tests/port/mock_drt_unittest.py261
-rw-r--r--Tools/Scripts/webkitpy/layout_tests/port/port_testcase.py12
-rw-r--r--Tools/Scripts/webkitpy/layout_tests/port/server_process.py6
-rw-r--r--Tools/Scripts/webkitpy/layout_tests/port/server_process_unittest.py77
-rw-r--r--Tools/Scripts/webkitpy/layout_tests/port/test.py221
-rw-r--r--Tools/Scripts/webkitpy/layout_tests/port/test_files.py58
-rw-r--r--Tools/Scripts/webkitpy/layout_tests/port/test_files_unittest.py57
-rw-r--r--Tools/Scripts/webkitpy/layout_tests/port/webkit.py53
-rw-r--r--Tools/Scripts/webkitpy/layout_tests/port/webkit_unittest.py36
-rw-r--r--Tools/Scripts/webkitpy/layout_tests/port/websocket_server.py2
-rw-r--r--Tools/Scripts/webkitpy/layout_tests/rebaseline_chromium_webkit_tests.py125
-rw-r--r--Tools/Scripts/webkitpy/layout_tests/rebaseline_chromium_webkit_tests_unittest.py184
-rwxr-xr-xTools/Scripts/webkitpy/layout_tests/run_webkit_tests.py33
-rw-r--r--Tools/Scripts/webkitpy/layout_tests/run_webkit_tests_unittest.py57
-rw-r--r--Tools/Scripts/webkitpy/layout_tests/test_types/image_diff.py60
-rw-r--r--Tools/Scripts/webkitpy/layout_tests/test_types/test_type_base.py63
-rw-r--r--Tools/Scripts/webkitpy/layout_tests/test_types/test_type_base_unittest.py2
-rw-r--r--Tools/Scripts/webkitpy/layout_tests/test_types/text_diff.py18
-rwxr-xr-xTools/Scripts/webkitpy/layout_tests/update_webgl_conformance_tests.py2
-rw-r--r--Tools/Scripts/webkitpy/style/checker.py27
-rwxr-xr-xTools/Scripts/webkitpy/style/checker_unittest.py25
-rw-r--r--Tools/Scripts/webkitpy/style/checkers/cpp.py36
-rw-r--r--Tools/Scripts/webkitpy/style/checkers/cpp_unittest.py55
-rw-r--r--Tools/Scripts/webkitpy/style/checkers/test_expectations.py3
-rw-r--r--Tools/Scripts/webkitpy/style/checkers/test_expectations_unittest.py35
-rw-r--r--Tools/Scripts/webkitpy/tool/bot/irc_command.py2
-rw-r--r--Tools/Scripts/webkitpy/tool/bot/sheriffircbot.py2
-rw-r--r--Tools/Scripts/webkitpy/tool/commands/__init__.py1
-rw-r--r--Tools/Scripts/webkitpy/tool/commands/commandtest.py4
-rw-r--r--Tools/Scripts/webkitpy/tool/commands/download.py2
-rw-r--r--Tools/Scripts/webkitpy/tool/commands/download_unittest.py12
-rw-r--r--Tools/Scripts/webkitpy/tool/commands/prettydiff.py2
-rw-r--r--Tools/Scripts/webkitpy/tool/commands/queries.py2
-rw-r--r--Tools/Scripts/webkitpy/tool/commands/roll.py48
-rw-r--r--Tools/Scripts/webkitpy/tool/commands/roll_unittest.py50
-rw-r--r--Tools/Scripts/webkitpy/tool/commands/stepsequence.py6
-rw-r--r--Tools/Scripts/webkitpy/tool/commands/upload.py6
-rw-r--r--Tools/Scripts/webkitpy/tool/commands/upload_unittest.py12
-rwxr-xr-xTools/Scripts/webkitpy/tool/main.py2
-rw-r--r--Tools/Scripts/webkitpy/tool/mocktool.py31
-rw-r--r--Tools/Scripts/webkitpy/tool/steps/__init__.py2
-rw-r--r--Tools/Scripts/webkitpy/tool/steps/preparechangelogfordepsroll.py40
-rw-r--r--Tools/Scripts/webkitpy/tool/steps/preparechangelogforrevert.py18
-rw-r--r--Tools/Scripts/webkitpy/tool/steps/preparechangelogforrevert_unittest.py130
-rw-r--r--Tools/Scripts/webkitpy/tool/steps/suggestreviewers_unittest.py5
-rw-r--r--Tools/Scripts/webkitpy/tool/steps/updatechromiumdeps.py64
-rw-r--r--Tools/Scripts/webkitpy/tool/steps/validatechangelogs_unittest.py5
-rw-r--r--Tools/TestWebKitAPI/JavaScriptTest.cpp65
-rw-r--r--Tools/TestWebKitAPI/JavaScriptTest.h32
-rw-r--r--Tools/TestWebKitAPI/PlatformWebView.h2
-rw-r--r--Tools/TestWebKitAPI/Test.h4
-rw-r--r--Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj14
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2/PageLoadBasic.cpp6
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2/RestoreSessionStateContainingFormData.cpp86
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2/SpacebarScrolling.cpp32
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2/simple-form.html11
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2/win/HideFindIndicator.cpp85
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2/win/ResizeViewWhileHidden.cpp125
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2/win/WMPrint.cpp46
-rw-r--r--Tools/TestWebKitAPI/mac/PlatformWebViewMac.mm2
-rw-r--r--Tools/TestWebKitAPI/win/PlatformWebViewWin.cpp7
-rw-r--r--Tools/TestWebKitAPI/win/TestWebKitAPI.vcproj24
-rwxr-xr-xTools/TestWebKitAPI/win/copy-resources.cmd1
-rw-r--r--Tools/Tools.pro15
-rw-r--r--Tools/WebKitTestRunner/Configurations/Base.xcconfig2
-rw-r--r--Tools/WebKitTestRunner/DerivedSources.pro2
-rw-r--r--Tools/WebKitTestRunner/InjectedBundle/Bindings/LayoutTestController.idl14
-rw-r--r--Tools/WebKitTestRunner/InjectedBundle/InjectedBundle.cpp8
-rw-r--r--Tools/WebKitTestRunner/InjectedBundle/InjectedBundle.h2
-rw-r--r--Tools/WebKitTestRunner/InjectedBundle/InjectedBundlePage.cpp87
-rw-r--r--Tools/WebKitTestRunner/InjectedBundle/InjectedBundlePage.h17
-rw-r--r--Tools/WebKitTestRunner/InjectedBundle/LayoutTestController.cpp30
-rw-r--r--Tools/WebKitTestRunner/InjectedBundle/LayoutTestController.h12
-rw-r--r--Tools/WebKitTestRunner/InjectedBundle/qt/ActivateFontsQt.cpp17
-rw-r--r--Tools/WebKitTestRunner/InjectedBundle/qt/InjectedBundle.pro8
-rw-r--r--Tools/WebKitTestRunner/TestController.cpp39
-rw-r--r--Tools/WebKitTestRunner/TestController.h3
-rw-r--r--Tools/WebKitTestRunner/TestInvocation.cpp19
-rw-r--r--Tools/WebKitTestRunner/WebKitTestRunner.xcodeproj/project.pbxproj6
-rw-r--r--Tools/WebKitTestRunner/WebKitTestRunnerPrefix.h1
-rw-r--r--Tools/WebKitTestRunner/mac/TestControllerMac.mm5
-rw-r--r--Tools/WebKitTestRunner/qt/TestControllerQt.cpp5
-rw-r--r--Tools/WebKitTestRunner/qt/WebKitTestRunner.pro4
-rw-r--r--Tools/WebKitTestRunner/win/TestControllerWin.cpp5
-rw-r--r--Tools/wx/browser/wscript2
-rw-r--r--Tools/wx/build/build_utils.py2
-rw-r--r--Tools/wx/build/settings.py3
236 files changed, 10827 insertions, 2066 deletions
diff --git a/Tools/BuildSlaveSupport/build.webkit.org-config/config.json b/Tools/BuildSlaveSupport/build.webkit.org-config/config.json
index 6e03f7a..07edacc 100644
--- a/Tools/BuildSlaveSupport/build.webkit.org-config/config.json
+++ b/Tools/BuildSlaveSupport/build.webkit.org-config/config.json
@@ -17,7 +17,9 @@
{ "name": "apple-macpro-3", "platform": "mac-snowleopard" },
{ "name": "apple-macpro-4", "platform": "mac-leopard" },
{ "name": "apple-macpro-5", "platform": "mac-leopard" },
- { "name": "apple-macpro-6", "platform": "mac-leopard" },
+ { "name": "apple-macpro-6", "platform": "mac-leopard" },
+ { "name": "apple-macpro-7", "platform": "mac-leopard" },
+
{ "name": "apple-windows-1", "platform": "win"},
{ "name": "apple-windows-2", "platform": "win"},
@@ -38,7 +40,6 @@
{ "name": "gtk-linux-slave-1", "platform": "gtk"},
{ "name": "gtk-linux-slave-2", "platform": "gtk"},
{ "name": "gtk-linux-slave-3", "platform": "gtk"},
- { "name": "gtk-linux-slave-4", "platform": "gtk"},
{ "name": "szeged-linux-1", "platform": "qt"},
{ "name": "szeged-linux-2", "platform": "qt"},
@@ -70,7 +71,7 @@
},
{ "name": "Leopard Intel Release (Tests)", "type": "Test", "builddir": "leopard-intel-release-tests",
"platform": "mac-leopard", "configuration": "release", "architectures": ["i386"],
- "slavenames": ["apple-macpro-4", "apple-pixel-1", "test-slave"]
+ "slavenames": ["apple-macpro-4", "apple-pixel-1", "test-slave", "apple-macpro-7"]
},
{ "name": "Leopard Intel Debug (Build)", "type": "Build", "builddir": "leopard-intel-debug",
@@ -80,7 +81,7 @@
},
{ "name": "Leopard Intel Debug (Tests)", "type": "Test", "builddir": "leopard-intel-debug-tests",
"platform": "mac-leopard", "configuration": "debug", "architectures": ["i386"],
- "slavenames": ["apple-xserve-3", "test-slave", "apple-macpro-5", "apple-macpro-6"]
+ "slavenames": ["apple-xserve-3", "test-slave", "apple-macpro-5", "apple-macpro-6", "apple-macpro-7"]
},
{ "name": "SnowLeopard Intel Release (Build)", "type": "Build", "builddir": "snowleopard-intel-release",
"platform": "mac-snowleopard", "configuration": "release", "architectures": ["x86_64"],
@@ -141,11 +142,6 @@
"slavenames": ["gtk-linux-slave-3"]
},
{
- "name": "GTK Linux 64-bit Release", "type": "BuildAndTest", "builddir": "gtk-linux-64-release",
- "platform": "gtk", "configuration": "release", "architectures": ["x86_64"],
- "slavenames": ["gtk-linux-slave-4"]
- },
- {
"name": "Qt Linux Release", "type": "BuildAndTest", "builddir": "qt-linux-release",
"platform": "qt", "configuration": "release", "architectures": ["i386"],
"slavenames": ["szeged-linux-1"]
@@ -230,7 +226,7 @@
"schedulers": [ { "type": "AnyBranchScheduler", "name": "trunk", "change_filter": "trunk_filter", "treeStableTimer": 45.0,
"builderNames": ["Leopard Intel Release (Build)", "Leopard Intel Debug (Build)",
"SnowLeopard Intel Release (Build)", "SnowLeopard Intel Leaks",
- "GTK Linux 32-bit Release", "GTK Linux 32-bit Debug", "GTK Linux 64-bit Debug", "GTK Linux 64-bit Release",
+ "GTK Linux 32-bit Release", "GTK Linux 32-bit Debug", "GTK Linux 64-bit Debug",
"Qt Linux Release", "Qt Linux Release minimal", "Qt Linux ARMv5 Release", "Qt Linux ARMv7 Release",
"Qt Windows 32-bit Release", "Qt Windows 32-bit Debug",
"Chromium Win Release", "Chromium Mac Release", "Chromium Linux Release",
diff --git a/Tools/BuildSlaveSupport/build.webkit.org-config/master.cfg b/Tools/BuildSlaveSupport/build.webkit.org-config/master.cfg
index 1ce5b88..4ee277c 100644
--- a/Tools/BuildSlaveSupport/build.webkit.org-config/master.cfg
+++ b/Tools/BuildSlaveSupport/build.webkit.org-config/master.cfg
@@ -318,8 +318,8 @@ class RunQtAPITests(shell.Test):
description = ["API tests running"]
descriptionDone = ["API tests"]
command = ["python", "./Tools/Scripts/run-qtwebkit-tests",
- "--output-file=qt-unit-tests.html", "--do-not-open-results", "--timeout=30",
- WithProperties("WebKitBuild/%(configuration_pretty)s/Source/WebKit/qt/tests/")]
+ "--output-file=qt-unit-tests.html", "--do-not-open-results", "--timeout=120",
+ WithProperties("WebKitBuild/%(configuration_pretty)s/WebKit/qt/tests/")]
def start(self):
self.setProperty("configuration_pretty", self.getProperty("configuration").title())
@@ -445,9 +445,10 @@ class TestFactory(Factory):
self.addStep(self.TestClass, skipBuild=(platform == 'win'))
# Tiger's Python 2.3 is too old. WebKit Python requires 2.5+.
# Sadly we have no way to detect the version on the slave from here.
- if platform != "mac-tiger":
+ if platform != "mac-tiger" and platform != "chromium-win":
self.addStep(RunPythonTests)
- self.addStep(RunPerlTests)
+ if platform != "chromium-win":
+ self.addStep(RunPerlTests)
self.addStep(ArchiveTestResults)
self.addStep(UploadTestResults)
self.addStep(ExtractTestResults)
diff --git a/Tools/BuildSlaveSupport/built-product-archive b/Tools/BuildSlaveSupport/built-product-archive
index 611d006..9dee922 100644
--- a/Tools/BuildSlaveSupport/built-product-archive
+++ b/Tools/BuildSlaveSupport/built-product-archive
@@ -89,7 +89,7 @@ def archiveBuiltProduct(configuration, platform):
shutil.rmtree(thinDirectory)
os.mkdir(thinDirectory)
- for dirname in ["bin", "lib", "Source/JavaScriptCore"]:
+ for dirname in ["bin", "lib", "JavaScriptCore"]:
fromDir = os.path.join(configurationBuildDirectory, dirname, "*")
toDir = os.path.join(thinDirectory, dirname)
os.makedirs(toDir)
diff --git a/Tools/BuildSlaveSupport/test-result-archive b/Tools/BuildSlaveSupport/test-result-archive
index af66bf0..a4d3ca3 100644
--- a/Tools/BuildSlaveSupport/test-result-archive
+++ b/Tools/BuildSlaveSupport/test-result-archive
@@ -46,7 +46,7 @@ def main():
if options.platform == 'chromium':
# See results_directory() in webkitpy/layout_tests/port/chromium.py.
layoutTestResultsDir = os.path.abspath(os.path.join(sourceRootDirectory,
- "WebKit", "chromium", "webkit", options.configuration.capitalize(),
+ "Source", "WebKit", "chromium", "webkit", options.configuration.capitalize(),
"layout-test-results"))
return archiveTestResults(options.configuration, options.platform, layoutTestResultsDir)
diff --git a/Tools/CMakeListsWinCE.txt b/Tools/CMakeListsWinCE.txt
index 89f6b97..7945daf 100644
--- a/Tools/CMakeListsWinCE.txt
+++ b/Tools/CMakeListsWinCE.txt
@@ -21,4 +21,5 @@ SET(WinCELauncher_LIBRARIES
INCLUDE_DIRECTORIES(${WinCELauncher_INCLUDE_DIRECTORIES})
ADD_EXECUTABLE(WinCELauncher ${WinCELauncher_SOURCES})
+ADD_DEPENDENCIES(WinCELauncher ${WebKit_LIBRARY_NAME})
TARGET_LINK_LIBRARIES(WinCELauncher ${WinCELauncher_LIBRARIES})
diff --git a/Tools/ChangeLog b/Tools/ChangeLog
index 3ef3b4a..4e59dae 100644
--- a/Tools/ChangeLog
+++ b/Tools/ChangeLog
@@ -1,3 +1,2692 @@
+2011-02-12 Chang Shu <cshu@webkit.org>
+
+ Unreviewed.
+
+ Update my own email addresses and IRC nickname.
+
+ * Scripts/webkitpy/common/config/committers.py:
+
+2011-02-11 Dirk Pranke <dpranke@chromium.org>
+
+ Reviewed by Tony Chang.
+
+ This patch adds to NRWT most of the support needed to run the new
+ message-based workers in separate threads or processes. The code
+ isn't fully complete yet because we don't support cancel() or
+ is_alive().
+
+ https://bugs.webkit.org/show_bug.cgi?id=54070
+
+ * Scripts/webkitpy/layout_tests/layout_package/manager_worker_broker.py:
+ * Scripts/webkitpy/layout_tests/layout_package/manager_worker_broker_unittest.py:
+ * Scripts/webkitpy/layout_tests/layout_package/test_runner2.py:
+ * Scripts/webkitpy/layout_tests/port/base.py:
+ * Scripts/webkitpy/layout_tests/port/mock_drt.py:
+ * Scripts/webkitpy/layout_tests/run_webkit_tests_unittest.py:
+
+2011-02-11 Sailesh Agrawal <sail@chromium.org>
+
+ Reviewed by Kenneth Russell.
+
+ plugins/invalidate_rect.html fails on chromium-mac
+ https://bugs.webkit.org/show_bug.cgi?id=54051
+
+ This change fixes the invalidate_rect.html test failure on Windows.
+
+ There were two problems. First, the test specified that the plugin was window less by doing <embed ... windowedPlugin="false"></embed>. The windowedPlugin parameter was never being read by the plugin. Fix was to simply set the NPPVpluginWindowBool variable based on the parameter.
+
+ The second problem was that the plugin never handled paint events on Windows. Fix was to simply copy the Mac code to handle paint events.
+
+ This change also updates the build path in chromium_win.py to use the new Source directory.
+
+ * DumpRenderTree/TestNetscapePlugIn/PluginObject.cpp:
+ (invalidateRect):
+ * DumpRenderTree/TestNetscapePlugIn/main.cpp:
+ (NPP_New):
+ (handleEventWin):
+ (NPP_HandleEvent):
+ * Scripts/webkitpy/layout_tests/port/chromium_win.py:
+
+2011-02-11 Csaba Osztrogonác <ossy@webkit.org>
+
+ Reviewed by Andreas Kling.
+
+ [Qt] Increase the timeout of Qt API tests to 120 seconds.
+
+ * BuildSlaveSupport/build.webkit.org-config/master.cfg:
+
+2011-02-10 Zhenyao Mo <zmo@google.com>
+
+ Unreviewed, build fix.
+
+ * DumpRenderTree/DumpRenderTree.gypi:
+
+2011-02-10 Dirk Pranke <dpranke@chromium.org>
+
+ Reviewed by Tony Chang.
+
+ This patch adds the bulk of the remaining functionality for
+ the NRWT message-passing implementation. The patch adds a new
+ Worker class that will eventually replace the TestShellThread
+ class in dump_render_tree_thread.py, and implements enough of
+ TestRunner2 and the inline version of the manager_worker_broker
+ to actually be able to send a full set of messages back and
+ forth. The Worker stubs do not actually run tests, and there's
+ lots of error handling and stats needed, but this is the core
+ logic.
+
+ https://bugs.webkit.org/show_bug.cgi?id=54068
+
+ * Scripts/webkitpy/layout_tests/layout_package/manager_worker_broker.py:
+ * Scripts/webkitpy/layout_tests/layout_package/manager_worker_broker_unittest.py:
+ * Scripts/webkitpy/layout_tests/layout_package/test_runner2.py:
+ * Scripts/webkitpy/layout_tests/layout_package/worker.py: Added.
+ * Scripts/webkitpy/layout_tests/run_webkit_tests_unittest.py:
+
+2011-02-10 Zhenyao Mo <zmo@google.com>
+
+ Unreviewed, build fix.
+
+ * DumpRenderTree/DumpRenderTree.gypi:
+
+2011-02-10 Zhenyao Mo <zmo@google.com>
+
+ Unreviewed, build fix.
+
+ * DumpRenderTree/DumpRenderTree.gypi:
+
+2011-02-10 Zhenyao Mo <zmo@google.com>
+
+ Unreviewed, attempt to fix crashing plugin tests.
+
+ * DumpRenderTree/DumpRenderTree.gypi:
+
+2011-02-10 Zhenyao Mo <zmo@google.com>
+
+ Unreviewed, build fix.
+
+ * DumpRenderTree/DumpRenderTree.gypi:
+
+2011-02-10 Sam Weinig <sam@webkit.org>
+
+ Try and fix some crashing tests on the chromium build bot.
+
+ * DumpRenderTree/DumpRenderTree.gypi:
+
+2011-02-10 Anders Carlsson <andersca@apple.com>
+
+ Reviewed by Sam Weinig.
+
+ Log an error if a plug-in test can't be found
+ https://bugs.webkit.org/show_bug.cgi?id=54252
+
+ * DumpRenderTree/TestNetscapePlugIn/PluginTest.cpp:
+ (PluginTest::create):
+ Return null if the test wasn't found.
+
+ * DumpRenderTree/TestNetscapePlugIn/main.cpp:
+ (NPP_New):
+ Report an error if PluginTest::create returns null.
+
+2011-02-10 Robert Hogan <robert@webkit.org>
+
+ Reviewed by Laszlo Gombos.
+
+ [Qt] Return menu items from eventSender.contextMenu()
+ https://bugs.webkit.org/show_bug.cgi?id=53039
+
+ * DumpRenderTree/qt/EventSenderQt.cpp:
+ (EventSender::contextClick):
+ * DumpRenderTree/qt/EventSenderQt.h:
+
+2011-02-10 Adam Roben <aroben@apple.com>
+
+ Test showing and hiding the find indicator on Windows
+
+ Test for <http://webkit.org/b/54213> <rdar://problem/8983261> REGRESSION (r78198): Crash in
+ FindIndicator::contentImage when scrolling page
+
+ Reviewed by Steve Falkenburg.
+
+ * TestWebKitAPI/Tests/WebKit2/win/HideFindIndicator.cpp: Added.
+ (TestWebKitAPI::didFinishLoadForFrame): Record that the load finished.
+ (TestWebKitAPI::findIndicatorCallback): Record that the callback was called, and save the
+ bitmap.
+ (TestWebKitAPI::initialize): Hook up our callbacks.
+ (TestWebKitAPI::TEST): Test showing then hiding the find indicator to see if we crash.
+
+ * TestWebKitAPI/PlatformWebView.h:
+ * TestWebKitAPI/mac/PlatformWebViewMac.mm:
+ (TestWebKitAPI::PlatformWebView::page):
+ * TestWebKitAPI/win/PlatformWebViewWin.cpp:
+ (TestWebKitAPI::PlatformWebView::page):
+ Made page a const member function.
+
+ * TestWebKitAPI/win/TestWebKitAPI.vcproj: Added the new test.
+
+2011-02-10 Mario Sanchez Prada <msanchez@igalia.com>
+
+ Reviewed by Martin Robinson.
+
+ [GTK] Log signals from AtkDocument interface also in AccessibilityController
+ https://bugs.webkit.org/show_bug.cgi?id=54198
+
+ Trace AtkDocument's signals emission through AccessibilityController.
+
+ Also, taken the code related to adding and removing global
+ listeners for ATK signals out to a separate file, for the sake of
+ clarity and to ease future additions.
+
+ * DumpRenderTree/gtk/AccessibilityCallbacks.h: Added.
+ * DumpRenderTree/gtk/AccessibilityCallbacks.cpp: Added
+ (printAccessibilityEvent): Print information about an event.
+ (axObjectEventListener): Global listener for AtkObject's signals.
+ (axDocumentEventListener): Global listener for AtkDocument's signals.
+ (connectAccessibilityCallbacks): Connect all global listeners.
+ (disconnectAccessibilityCallbacks): Disconnect all global listeners.
+
+ * DumpRenderTree/gtk/AccessibilityControllerGtk.cpp:
+ (AccessibilityController::setLogAccessibilityEvents): Call to
+ connectAccessibilityCallbacks and disconnectAccessibilityCallbacks.
+
+ * GNUmakefile.am: Added new files.
+
+2011-02-09 Martin Robinson <mrobinson@igalia.com>
+
+ Reviewed by Gustavo Noronha Silva.
+
+ [GTK] Default error page is interfering with tests which require failed loads
+ https://bugs.webkit.org/show_bug.cgi?id=54157
+
+ Disable the default error page during DRT runs. This prevents unexpected loads
+ from interfering with tests that have planned failed loads.
+
+ * DumpRenderTree/gtk/DumpRenderTree.cpp:
+ (webViewLoadError): Added, disable default handler.
+ (createWebView): Connect the new load-error handler.
+
+2011-02-10 Zoltan Horvath <zoltan@webkit.org>
+
+ Reviewed by Andreas Kling.
+
+ [Qt] Add UrlLoader and command line argument handling to MiniBrowser
+ https://bugs.webkit.org/show_bug.cgi?id=54192
+
+ Copy and modify files from QtTestBrowser's implementation.
+
+ * MiniBrowser/qt/BrowserWindow.cpp:
+ (BrowserWindow::BrowserWindow):
+ (BrowserWindow::newWindow):
+ * MiniBrowser/qt/BrowserWindow.h:
+ * MiniBrowser/qt/MiniBrowser.pro:
+ * MiniBrowser/qt/MiniBrowserApplication.cpp: Copied from QtTestBrowser/launcherwindow.cpp
+ (MiniBrowserApplication::MiniBrowserApplication):
+ (MiniBrowserApplication::handleUserOptions):
+ * MiniBrowser/qt/MiniBrowserApplication.h: Copied from QtTestBrowser/launcherwindow.h
+ (WindowOptions::WindowOptions):
+ (MiniBrowserApplication::urls):
+ (MiniBrowserApplication::isRobotized):
+ (MiniBrowserApplication::robotTimeout):
+ (MiniBrowserApplication::robotExtraTime):
+ * MiniBrowser/qt/UrlLoader.cpp: Copied from QtTestBrowser/urlloader.cpp
+ (UrlLoader::UrlLoader):
+ (UrlLoader::loadNext):
+ (UrlLoader::checkIfFinished):
+ (UrlLoader::frameLoadStarted):
+ (UrlLoader::frameLoadFinished):
+ (UrlLoader::loadUrlList):
+ (UrlLoader::getUrl):
+ * MiniBrowser/qt/UrlLoader.h: Copied from QtTestBrowser/urlloader.h
+ * MiniBrowser/qt/main.cpp:
+ (main):
+ * MiniBrowser/qt/utils.cpp: Copied from QtTestBrowser/utils.cpp
+ (takeOptionValue):
+ (formatKeys):
+ (enumToKeys):
+ (appQuit):
+ (urlFromUserInput):
+ * MiniBrowser/qt/utils.h: Copied from QtTestBrowser/utils.h
+
+2011-02-10 Zoltan Horvath <zoltan@webkit.org>
+
+ Reviewed by Andreas Kling.
+
+ check-webkit-style: Add -build/include exemption for Tools/MiniBrowser/qt
+ https://bugs.webkit.org/show_bug.cgi?id=54200
+
+ * Scripts/webkitpy/style/checker.py:
+ * Scripts/webkitpy/style/checker_unittest.py:
+
+2011-02-10 Peter Varga <pvarga@webkit.org>
+
+ Reviewed by Csaba Osztrogonác.
+
+ Remove PCRE source from trunk
+ https://bugs.webkit.org/show_bug.cgi?id=54188
+
+ * wx/build/settings.py:
+
+2011-02-10 David Levin <levin@chromium.org>
+
+ Reviewed by Shinichiro Hamaji.
+
+ check-webkit-style should be able to figure out function modifiers and return type.
+ https://bugs.webkit.org/show_bug.cgi?id=54124
+
+ * Scripts/webkitpy/style/checkers/cpp.py:
+ (_rfind_in_lines): A way to search backwards in lines.
+ (_FunctionState.modifiers_and_return_type):
+ * Scripts/webkitpy/style/checkers/cpp_unittest.py: Added tests for the new functionality.
+
+2011-02-09 Adam Roben <aroben@apple.com>
+
+ Test that WM_PRINT doesn't trigger an assertion
+
+ Test for <http://webkit.org/b/54145> <rdar://problem/8979559> WM_PRINT doesn't work with new
+ drawing area (assertion failure in DrawingAreaProxyImpl in Debug builds)
+
+ Reviewed by Darin Adler.
+
+ * TestWebKitAPI/Tests/WebKit2/win/WMPrint.cpp: Added.
+ (TestWebKitAPI::TEST): Send a WM_PRINT message to a WKView.
+
+2011-02-09 Adam Roben <aroben@apple.com>
+
+ Test that having a WKView paint after being resized while hidden doesn't cause a crash
+
+ Test for <http://webkit.org/b/54142> <rdar://problem/8979365> Crash in
+ DrawingAreaProxyImpl::paint when WKView paints after being resized while hidden
+
+ Reviewed by Darin Adler.
+
+ * TestWebKitAPI/Tests/WebKit2/win/ResizeViewWhileHidden.cpp:
+ (TestWebKitAPI::TEST): Force the WKView to paint after resizing it while hidden.
+
+2011-02-09 Adam Roben <aroben@apple.com>
+
+ Add a test that resizes a WKView while it's hidden
+
+ Test for <http://webkit.org/b/54141> <rdar://problem/8979195> WKView draws at wrong size,
+ performs badly if is resized while hidden (assertion fails in
+ BackingStore::incorporateUpdate in Debug builds)
+
+ Reviewed by Darin Adler.
+
+ * TestWebKitAPI/Tests/WebKit2/win/ResizeViewWhileHidden.cpp: Added.
+ (TestWebKitAPI::didFinishLoadForFrame): Record that the load finished.
+ (TestWebKitAPI::setPageLoaderClient): Hook up our didFinishLoadForFrame callback.
+ (TestWebKitAPI::flushMessages): Load a URL and wait for the load to complete. This ensures
+ that all pending messages have been handled by the UI and web process.
+ (TestWebKitAPI::timerCallback): Kill the timer and record that it fired.
+ (TestWebKitAPI::runForDuration): Set a timer and run the run loop until it fires.
+ (TestWebKitAPI::waitForBackingStoreUpdate): Wait for half a second to give the web process a
+ chance to display, then flush all pending messages.
+ (TestWebKitAPI::TEST): Resize the WKView while it's hidden, then show it again and wait for
+ the backing store to update. This triggers the assertion from bug 54141.
+
+ * TestWebKitAPI/win/PlatformWebViewWin.cpp:
+ (TestWebKitAPI::PlatformWebView::resizeTo): Implemented.
+
+ * TestWebKitAPI/win/TestWebKitAPI.vcproj: Added new test.
+
+2011-02-10 Philippe Normand <pnormand@igalia.com>
+
+ Unreviewed, GTK build fix after roll out of r78157...
+
+ * GNUmakefile.am:
+
+2011-02-10 Eric Seidel <eric@webkit.org>
+
+ Unreviewed, rolling out r78157.
+ http://trac.webkit.org/changeset/78157
+ https://bugs.webkit.org/show_bug.cgi?id=54150
+
+ Fails on a bunch of bots
+
+ * DumpRenderTree/DumpRenderTree.xcodeproj/project.pbxproj:
+ * DumpRenderTree/TestNetscapePlugIn/Tests/EvaluateJSDestroyingPluginFromDestroyStream.cpp: Removed.
+ * DumpRenderTree/TestNetscapePlugIn/win/TestNetscapePlugin.vcproj:
+ * DumpRenderTree/qt/TestNetscapePlugin/TestNetscapePlugin.pro:
+
+2011-02-10 Mario Sanchez Prada <msanchez@igalia.com>
+
+ Reviewed by Xan Lopez.
+
+ [GTK] Reset GTK' DRT's AccessibilityController to consistent value before every test
+ https://bugs.webkit.org/show_bug.cgi?id=54185
+
+ * DumpRenderTree/gtk/DumpRenderTree.cpp:
+ (resetDefaultsToConsistentValues):
+
+2011-02-10 Philippe Normand <pnormand@igalia.com>
+
+ Unreviewed GTK build fix.
+
+ Adding
+ Tools/DumpRenderTree/TestNetscapePlugIn/Tests/EvaluateJSDestroyingPluginFromDestroyStream.cpp
+ in the build, fixing the
+ plugins/npruntime/evaluate-js-destroying-plugin-from-destroy-stream.html
+ test.
+
+ * GNUmakefile.am:
+
+2011-02-10 Mario Sanchez Prada <msanchez@igalia.com>
+
+ Reviewed by Chris Fleizach.
+
+ [GTK] Add support in DRT to log "accessibility events"
+ https://bugs.webkit.org/show_bug.cgi?id=54116
+
+ Added a way to log accessibility related events, in a
+ platform-dependant way.
+
+ Add new function to AccessibilityController.
+
+ * DumpRenderTree/AccessibilityController.h:
+ * DumpRenderTree/AccessibilityController.cpp:
+ (logAccessibilityEventsCallback): New callback.
+ (AccessibilityController::getJSClass): Added new function.
+ (AccessibilityController::resetToConsistentState): Initialized
+ calling setLogAccessibilityEvents(false).
+
+ Provided implementation for the GTK port.
+
+ * DumpRenderTree/gtk/AccessibilityControllerGtk.cpp:
+ (accessibility_event_listener): Common listener for logging
+ information about all the signals emitted by any AtkObject.
+ (AccessibilityController::setLogAccessibilityEvents): Add or
+ remove listeners for signals, as specified by the parameter.
+
+ Provide dummy implementations for mac and win ports.
+
+ * DumpRenderTree/mac/AccessibilityControllerMac.mm:
+ (AccessibilityController::setLogAccessibilityEvents):
+ * DumpRenderTree/win/AccessibilityControllerWin.cpp:
+ (AccessibilityController::setLogAccessibilityEvents):
+
+2011-02-09 Hayato Ito <hayato@chromium.org>
+
+ Reviewed by Tony Chang.
+
+ [NRWT] Remove encoding parameters where we can assume data can be
+ written in binary mode.
+
+ https://bugs.webkit.org/show_bug.cgi?id=54066
+
+ * Scripts/webkitpy/layout_tests/layout_package/single_test_runner.py:
+ * Scripts/webkitpy/layout_tests/port/base.py:
+
+2011-02-09 Dirk Pranke <dpranke@chromium.org>
+
+ Reviewed by Tony Chang.
+
+ nrwt multiprocessing: minor cleanup prior to implementing the new worker
+
+ This patch renames AbstractManager to ManagerConnection and
+ changes some argument names to be more consistent between
+ manager_worker_broker and message_broker. It also fixes a couple
+ of typos in message_broker. These changes will be tested by code
+ introduced in the next patch.
+
+ https://bugs.webkit.org/show_bug.cgi?id=54067
+
+ * Scripts/webkitpy/layout_tests/layout_package/manager_worker_broker.py:
+ * Scripts/webkitpy/layout_tests/layout_package/message_broker2.py:
+
+2011-02-09 Anders Carlsson <andersca@apple.com>
+
+ Reviewed by Sam Weinig.
+
+ Repro crash with Sony Google TV ad at Gizmodo
+ https://bugs.webkit.org/show_bug.cgi?id=54150
+ <rdar://problem/8782346>
+
+ Add a new plug-in test that runs JavaScript that destroys the plug-in from within its NPN_DestroyStream callback.
+
+ * DumpRenderTree/DumpRenderTree.xcodeproj/project.pbxproj:
+ * DumpRenderTree/TestNetscapePlugIn/Tests/EvaluateJSDestroyingPluginFromDestroyStream.cpp: Added.
+ (EvaluateJSDestroyingPluginFromDestroyStream::EvaluateJSDestroyingPluginFromDestroyStream):
+ (EvaluateJSDestroyingPluginFromDestroyStream::NPP_Destroy):
+ (EvaluateJSDestroyingPluginFromDestroyStream::NPP_DestroyStream):
+ * DumpRenderTree/TestNetscapePlugIn/win/TestNetscapePlugin.vcproj:
+ * DumpRenderTree/qt/TestNetscapePlugin/TestNetscapePlugin.pro:
+
+2011-02-09 David Levin <levin@chromium.org>
+
+ Reviewed by Eric Seidel.
+
+ check-webkit-style: The error message about NULL should be more clear for comments.
+ https://bugs.webkit.org/show_bug.cgi?id=53786
+
+ * Scripts/webkitpy/style/checkers/cpp.py: Clarified the error message.
+ * Scripts/webkitpy/style/checkers/cpp_unittest.py: Fixed the corresponding test.
+
+2011-02-09 Nebojsa Ciric <cira@chromium.org>
+
+ Reviewed by Darin Fisher.
+
+ Implements Locale object of JavaScript internationalization API proposal, as an
+ v8 extension. Extension code is hosted in v8 project (src/extensions/experimental/i18n-extension.{cc,h})
+ and in this patch we just provide flags, tests and build rules for chromium port.
+ https://bugs.webkit.org/show_bug.cgi?id=49414
+
+ * DumpRenderTree/chromium/TestShell.cpp:
+ (TestShell::TestShell):
+
+2011-02-09 Laszlo Gombos <laszlo.1.gombos@nokia.com>
+
+ Reviewed by Kenneth Rohde Christiansen.
+
+ [Qt] Remove UiTools dependency from MiniBrowser
+ https://bugs.webkit.org/show_bug.cgi?id=54096
+
+ * MiniBrowser/qt/MiniBrowser.pro:
+
+2011-02-08 Hayato Ito <hayato@chromium.org>
+
+ Reviewed by Tony Chang.
+
+ [NRWT] Pull up rebaseline code from compare_output() function defined
+ in text_diff.py and image_diff.py into a SingleTestRunner.
+
+ This patch is a first step for eliminating test_type/* classes.
+
+ https://bugs.webkit.org/show_bug.cgi?id=53071
+
+ * Scripts/webkitpy/layout_tests/layout_package/single_test_runner.py:
+ * Scripts/webkitpy/layout_tests/test_types/image_diff.py:
+ * Scripts/webkitpy/layout_tests/test_types/test_type_base.py:
+ * Scripts/webkitpy/layout_tests/test_types/text_diff.py:
+
+2011-02-07 Ojan Vafai <ojan@chromium.org>
+
+ Reviewed by Mihai Parparita.
+
+ stop generating results.json files
+ https://bugs.webkit.org/show_bug.cgi?id=53977
+
+ We've only used incremental_results.json for a while now
+ and there are plans to start generating a results.json file that matches
+ the format of unexpected_results.json.
+
+ * Scripts/webkitpy/layout_tests/layout_package/json_layout_results_generator.py:
+ * Scripts/webkitpy/layout_tests/layout_package/json_results_generator.py:
+ * Scripts/webkitpy/layout_tests/layout_package/json_results_generator_unittest.py:
+ * Scripts/webkitpy/layout_tests/layout_package/test_runner.py:
+ * Scripts/webkitpy/layout_tests/run_webkit_tests.py:
+
+2011-02-08 Sailesh Agrawal <sail@chromium.org>
+
+ Reviewed by Kenneth Russell.
+
+ Invalidate rect doesn't work for windowless plugins on Chromium
+ https://bugs.webkit.org/show_bug.cgi?id=53117
+
+ Added two new utility methods.
+ - layoutTestController.displayInvalidatedRegion() does a paint of any area that has been invalidated. This is different from layoutTestController.display() which explicitly invalidates the entire page then paints.
+ - plugin.invalidateRect(left, top, right, bottom) - invalidates the given rect
+ This is used to test that invalidating a rect correctly causes a repaint of the plugin.
+
+ * DumpRenderTree/LayoutTestController.cpp:
+ (displayInvalidatedRegionCallback):
+ (LayoutTestController::staticFunctions):
+ * DumpRenderTree/LayoutTestController.h:
+ * DumpRenderTree/TestNetscapePlugIn/PluginObject.cpp:
+ (invalidateRect):
+ (pluginInvoke):
+ * DumpRenderTree/chromium/LayoutTestController.cpp:
+ (LayoutTestController::LayoutTestController):
+ (LayoutTestController::displayInvalidatedRegion):
+ * DumpRenderTree/chromium/LayoutTestController.h:
+ * Scripts/webkitpy/layout_tests/port/chromium_gpu.py:
+
+2011-02-08 Dirk Pranke <dpranke@chromium.org>
+
+ Reviewed by Tony Chang.
+
+ new-run-webkit-tests: move the logic that starts and stops the
+ servers from dump_render_tree_thread into single_test_runner
+ so that we can reuse it in the new multiprocessing worker class
+ as well.
+
+ https://bugs.webkit.org/show_bug.cgi?id=53840
+
+ * Scripts/webkitpy/layout_tests/layout_package/dump_render_tree_thread.py:
+ * Scripts/webkitpy/layout_tests/layout_package/single_test_runner.py:
+
+2011-02-08 Dirk Pranke <dpranke@chromium.org>
+
+ Reviewed by Mihai Parparita.
+
+ new-run-webkit-tests: split out thread stack logging code into a sharable module
+
+ This patch splits out the code used to find and log thread
+ stacks from NRWT-specific packages to something generic and
+ shareable by other python modules. It will be shared in the near
+ future by the manager_worker_broker module, for example.
+
+ https://bugs.webkit.org/show_bug.cgi?id=53656
+
+ * Scripts/webkitpy/common/system/stack_utils.py: Added.
+ * Scripts/webkitpy/common/system/stack_utils_unittest.py: Added.
+ * Scripts/webkitpy/layout_tests/layout_package/message_broker.py:
+ * Scripts/webkitpy/layout_tests/layout_package/message_broker_unittest.py:
+
+2011-02-08 Dirk Pranke <dpranke@chromium.org>
+
+ Reviewed by Tony Chang.
+
+ new-run-webkit-tests: move a bunch of testing logic out of
+ dump_render_tree_thread and into single_test_runner so that we
+ will be able to reuse it in the new multiprocessing worker class as well.
+
+ https://bugs.webkit.org/show_bug.cgi?id=53838
+
+ * Scripts/webkitpy/layout_tests/layout_package/dump_render_tree_thread.py:
+ * Scripts/webkitpy/layout_tests/layout_package/single_test_runner.py:
+
+
+2011-02-08 Dirk Pranke <dpranke@chromium.org>
+
+ Reviewed by Ojan Vafai.
+
+ new-run-webkit-tests: remove no longer needed WatchableThread
+ class.
+
+ https://bugs.webkit.org/show_bug.cgi?id=53839
+
+ * Scripts/webkitpy/layout_tests/layout_package/dump_render_tree_thread.py:
+
+2011-02-08 Dirk Pranke <dpranke@chromium.org>
+
+ Reviewed by Tony Chang.
+
+ new-run-webkit-tests: add stubs for the Manager objects that
+ will abstract the concurrency implementation (inline / threads /
+ processes). These classes do nothing yet and are not wired up to
+ anything.
+
+ https://bugs.webkit.org/show_bug.cgi?id=53477
+
+ * Scripts/webkitpy/layout_tests/layout_package/manager_worker_broker.py: Added.
+ * Scripts/webkitpy/layout_tests/layout_package/manager_worker_broker_unittest.py: Added.
+
+2011-02-08 Dirk Pranke <dpranke@chromium.org>
+
+ Reviewed by Tony Chang.
+
+ new-run-webkit-tests: add simplified message broker for new-style
+ messaging. This change adds a very simple message broker that
+ will be used to shuttle messages between the TestRunner2 manager
+ thread and the Worker threads. For now the class is not used by
+ anything, but the eventual usage can be seen in the patches
+ attached to bug 49566.
+
+ https://bugs.webkit.org/show_bug.cgi?id=53158
+
+ * Scripts/webkitpy/layout_tests/layout_package/message_broker2.py: Added.
+ * Scripts/webkitpy/layout_tests/layout_package/message_broker2_unittest.py: Added.
+
+2011-02-08 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Dimitri Glazkov.
+
+ chromium-win builder shouldn't run python or perl tests
+ https://bugs.webkit.org/show_bug.cgi?id=54032
+
+ These tests don't pass on this builder because the builder isn't
+ running in cygwin. There isn't really any point in running them and
+ making the bot red forever.
+
+ * BuildSlaveSupport/build.webkit.org-config/master.cfg:
+
+2011-02-08 Brady Eidson <beidson@apple.com>
+
+ Reviewed by Darin Adler.
+
+ <rdar://problem/8972913> and https://bugs.webkit.org/show_bug.cgi?id=54036
+ didChangeBackForwardList should include some context about what changed
+
+ * MiniBrowser/mac/BrowserWindowController.m:
+ (didChangeBackForwardList):
+
+2011-02-08 Sam Weinig <sam@webkit.org>
+
+ Reviewed by Anders Carlsson.
+
+ WK2: Add ability to pass context to policy delegate methods
+ https://bugs.webkit.org/show_bug.cgi?id=54031
+
+ * MiniBrowser/mac/BrowserWindowController.m:
+ (decidePolicyForNavigationAction):
+ (decidePolicyForNewWindowAction):
+ (decidePolicyForMIMEType):
+ * TestWebKitAPI/Tests/WebKit2/PageLoadBasic.cpp:
+ (TestWebKitAPI::decidePolicyForNavigationAction):
+ (TestWebKitAPI::decidePolicyForNewWindowAction):
+ (TestWebKitAPI::decidePolicyForMIMEType):
+ Update policy client for new API.
+
+2011-02-08 Martin Robinson <mrobinson@igalia.com>
+
+ Reviewed by Xan Lopez.
+
+ [GTK] DRT needs an implementation of LayoutTestController.setIconDatabaseEnabled
+ https://bugs.webkit.org/show_bug.cgi?id=54033
+
+ Add an implementation of LayoutTestController.setIconDatabaseEnabled that just
+ call DumpRenderTreeSupportGtk. Turn off the icon database between tests.
+
+ * DumpRenderTree/gtk/DumpRenderTree.cpp:
+ (resetDefaultsToConsistentValues): Turn off the icon database.
+ * DumpRenderTree/gtk/LayoutTestControllerGtk.cpp:
+ (LayoutTestController::setIconDatabaseEnabled): Call the appropriate DumpRenderTreeSupportGtk
+ method.
+
+2011-02-08 Kundu Suchismita <suchi.kundu@nokia.com>
+
+ Reviewed by Laszlo Gombos.
+
+ Local Storage settings can be enable/disable from "Develop" menu
+ https://bugs.webkit.org/show_bug.cgi?id=52296
+
+ * QtTestBrowser/launcherwindow.cpp:
+ (LauncherWindow::createChrome):
+ (LauncherWindow::toggleLocalStorage):
+ (LauncherWindow::toggleOfflineStorageDatabase):
+ (LauncherWindow::toggleOfflineWebApplicationCache):
+ (LauncherWindow::setOfflineStorageDefaultQuota):
+ * QtTestBrowser/launcherwindow.h:
+ (WindowOptions::WindowOptions):
+ * QtTestBrowser/main.cpp:
+ (LauncherApplication::handleUserOptions):
+
+2011-02-08 Martin Robinson <mrobinson@igalia.com>
+
+ Reviewed by Eric Seidel.
+
+ [GTK] EventSender.keyDown does not support non-array modifier arguments
+ https://bugs.webkit.org/show_bug.cgi?id=53962
+
+ Support handling either an array or a string for the modifier argument
+ to EventSender.keyDown.
+
+ * DumpRenderTree/gtk/EventSender.cpp:
+ (gdkModifierFromJSValue): Added this helper which factors out the
+ string comparison bits.
+ (gdkModifersFromJSValue): Test up front whether the value is a string,
+ to handle it specially.
+
+2011-02-08 Benjamin Poulain <ikipou@gmail.com>
+
+ Reviewed by Csaba Osztrogonác.
+
+ openDatabaseSync() stop responding after too many call
+ https://bugs.webkit.org/show_bug.cgi?id=53945
+
+ Reset the database quota to a known state between each test.
+
+ Define a quota for the known origins at each test run and delete
+ all the databases.
+ This way, the database related test do not depend on previous
+ allocations.
+
+ * DumpRenderTree/qt/DumpRenderTreeQt.cpp:
+ (WebCore::DumpRenderTree::resetToConsistentStateBeforeTesting):
+ (WebCore::DumpRenderTree::dumpDatabaseQuota):
+ * DumpRenderTree/qt/LayoutTestControllerQt.cpp:
+ (LayoutTestController::reset):
+
+2011-02-08 Carlos Garcia Campos <cgarcia@igalia.com>
+
+ Reviewed by Martin Robinson.
+
+ [GTK] DRT's TextInputController is unimplemented on GTK
+ https://bugs.webkit.org/show_bug.cgi?id=52997
+
+ Initial implementation of TextInputController for GTK port.
+
+ * DumpRenderTree/gtk/DumpRenderTree.cpp:
+ (webViewWindowObjectCleared):
+ * DumpRenderTree/gtk/TextInputController.cpp: Added.
+ (setMarkedTextCallback):
+ (insertTextCallback):
+ (unmarkTextCallback):
+ (firstRectForCharacterRangeCallback):
+ (selectedRangeCallback):
+ (getClass):
+ (makeTextInputController):
+ * DumpRenderTree/gtk/TextInputController.h: Added.
+ * GNUmakefile.am:
+
+2011-02-07 Tony Chang <tony@chromium.org>
+
+ Reviewed by Adam Barth.
+
+ clean up python imports
+ https://bugs.webkit.org/show_bug.cgi?id=53966
+
+ Convert "import A.B.C.D as D" to "from A.B.C import D" and
+ make some imports absolute as required by PEP-8
+
+ * Scripts/webkitpy/common/checkout/scm.py:
+ * Scripts/webkitpy/common/net/irc/ircbot.py:
+ * Scripts/webkitpy/common/system/logutils.py:
+ * Scripts/webkitpy/common/system/logutils_unittest.py:
+ * Scripts/webkitpy/layout_tests/deduplicate_tests.py:
+ * Scripts/webkitpy/layout_tests/port/chromium.py:
+ * Scripts/webkitpy/layout_tests/port/mac.py: Remove some unused imports
+ * Scripts/webkitpy/layout_tests/port/webkit.py:
+ * Scripts/webkitpy/layout_tests/update_webgl_conformance_tests.py:
+ * Scripts/webkitpy/tool/bot/irc_command.py:
+ * Scripts/webkitpy/tool/bot/sheriffircbot.py:
+ * Scripts/webkitpy/tool/commands/download.py:
+ * Scripts/webkitpy/tool/commands/prettydiff.py:
+ * Scripts/webkitpy/tool/commands/queries.py:
+ * Scripts/webkitpy/tool/commands/roll.py:
+ * Scripts/webkitpy/tool/commands/stepsequence.py:
+ * Scripts/webkitpy/tool/commands/upload.py:
+ * Scripts/webkitpy/tool/main.py:
+
+2011-02-07 James Robinson <jamesr@chromium.org>
+
+ Reviewed by Adam Barth.
+
+ Teach do-webcore-rename about the WebKit move to Source/
+ https://bugs.webkit.org/show_bug.cgi?id=53967
+
+ * Scripts/do-webcore-rename:
+
+2011-02-07 Maciej Stachowiak <mjs@apple.com>
+
+ Reviewed by Dan Bernstein.
+
+ Add resource load client for injected bundle and move willSendRequest there
+ https://bugs.webkit.org/show_bug.cgi?id=53972
+
+ * MiniBrowser/mac/WebBundle/WebBundleMain.m:
+ (didCreatePage):
+ * WebKitTestRunner/InjectedBundle/InjectedBundlePage.cpp:
+ (WTR::InjectedBundlePage::InjectedBundlePage):
+ (WTR::InjectedBundlePage::didInitiateLoadForResource):
+ (WTR::InjectedBundlePage::didReceiveResponseForResource):
+ (WTR::InjectedBundlePage::didReceiveContentLengthForResource):
+ (WTR::InjectedBundlePage::didFinishLoadForResource):
+ (WTR::InjectedBundlePage::didFailLoadForResource):
+ (WTR::InjectedBundlePage::willSendRequestForFrame):
+ * WebKitTestRunner/InjectedBundle/InjectedBundlePage.h:
+
+2011-02-07 Adam Barth <abarth@webkit.org>
+
+ Add Leopard Debug back to the core builders.
+
+ * Scripts/webkitpy/common/net/buildbot/buildbot.py:
+ * Scripts/webkitpy/common/net/buildbot/buildbot_unittest.py:
+
+2011-02-07 Adam Klein <adamk@chromium.org>
+
+ Reviewed by Jian Li.
+
+ [chromium] Remove deprecated method WebNotification::dir
+ https://bugs.webkit.org/show_bug.cgi?id=53735
+
+ * DumpRenderTree/chromium/NotificationPresenter.cpp:
+ (NotificationPresenter::show):
+
+2011-02-07 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ Remove Leopard Debug as a core builder
+ https://bugs.webkit.org/show_bug.cgi?id=53971
+
+ The Leopard Debug builder has been failing to compile for several days.
+ My understanding is that folks are working on fixing the build, but for
+ the time being we should probably remove it from the list of core
+ builders so that the core waterfall can be green. We can certainly add
+ it back once the build is fixed.
+
+ Also, I've removed the Tiger builders because those no longer appear to
+ be attached to the buildbot master.
+
+ * Scripts/webkitpy/common/net/buildbot/buildbot.py:
+ * Scripts/webkitpy/common/net/buildbot/buildbot_unittest.py:
+
+2011-02-01 Ojan Vafai <ojan@chromium.org>
+
+ Reviewed by Adam Roben.
+
+ include svn revisions in git diffs for the code review tool to use
+ https://bugs.webkit.org/show_bug.cgi?id=53569
+
+ * Scripts/webkitpy/common/checkout/scm.py:
+ * Scripts/webkitpy/common/checkout/scm_unittest.py:
+
+2011-02-03 MORITA Hajime <morrita@google.com>
+
+ Reviewed by Darin Fisher.
+
+ [Chromium] Should implement EditorClientImpl::requestCheckingOfString()
+ https://bugs.webkit.org/show_bug.cgi?id=51013
+
+ Gave DRT implementation for requestTextCheck().
+
+ * DumpRenderTree/chromium/LayoutTestController.cpp:
+ (LayoutTestController::setAsynchronousSpellCheckingEnabled): Implemented.
+ * DumpRenderTree/chromium/WebViewHost.cpp:
+ (invokeFinishLastTextCheck): Added.
+ (WebViewHost::requestTextCheck): Added.
+ (WebViewHost::finishLastTextCheck): Added.
+ * DumpRenderTree/chromium/WebViewHost.h:
+
+2011-02-07 Joone Hur <joone.hur@collabora.co.uk>
+
+ Reviewed by Martin Robinson.
+
+ [Gtk] Implement layoutTestController.findString
+ https://bugs.webkit.org/show_bug.cgi?id=50237
+
+ * DumpRenderTree/gtk/LayoutTestControllerGtk.cpp:
+ (LayoutTestController::findString):
+
+2011-02-07 Chang Shu <chang.shu@nokia.com>
+
+ Reviewed by Darin Adler.
+
+ We should disable spatial navigation explicitly during the initialization
+ of DumpRenderTree.
+ https://bugs.webkit.org/show_bug.cgi?id=53928
+
+ * DumpRenderTree/mac/DumpRenderTree.mm:
+ (resetDefaultsToConsistentValues):
+
+2011-02-07 Maciej Stachowiak <mjs@apple.com>
+
+ Not reviewed.
+
+ Fix WebKitTestRunner build on the SL bot.
+
+ * WebKitTestRunner/Configurations/Base.xcconfig: Look for the JSC copy
+ of ICU headers.
+
+2011-02-07 Csaba Osztrogonác <ossy@webkit.org>
+
+ Unreviewed.
+
+ [Qt][WK2] Buildfix after r77794.
+
+ WebKitTestRunner does not block remote resources or complain about them
+ https://bugs.webkit.org/show_bug.cgi?id=42139
+ <rdar://problem/8183942>
+
+ * WebKitTestRunner/InjectedBundle/qt/InjectedBundle.pro: Add missing includepaths.
+
+2011-02-07 Maciej Stachowiak <mjs@apple.com>
+
+ Not reviewed.
+
+ More bot appeasement.
+
+ * WebKitTestRunner/WebKitTestRunner.xcodeproj/project.pbxproj:
+
+2011-02-07 Maciej Stachowiak <mjs@apple.com>
+
+ Not reviewed.
+
+ Remove accidental references to directories on my laptop.
+
+ * WebKitTestRunner/WebKitTestRunner.xcodeproj/project.pbxproj:
+
+2011-02-07 Maciej Stachowiak <mjs@apple.com>
+
+ Reviewed by Antti Koivisto.
+
+ WebKitTestRunner does not block remote resources or complain about them
+ https://bugs.webkit.org/show_bug.cgi?id=42139
+ <rdar://problem/8183942>
+
+ * WebKitTestRunner/InjectedBundle/InjectedBundlePage.cpp:
+ (WTR::InjectedBundlePage::willSendRequestForFrame): Implement the required
+ checks (using KURL, to avoid need to invent a whole URL API).
+ * WebKitTestRunner/WebKitTestRunner.xcodeproj/project.pbxproj: Link WebCore
+ directly to get at KURL symbols.
+
+2011-02-06 Maciej Stachowiak <mjs@apple.com>
+
+ Reviewed by Daniel Bates.
+
+ Add WebKit2 bot to list of expected builders in Python regression test results.
+ https://bugs.webkit.org/show_bug.cgi?id=53905
+
+ * Scripts/webkitpy/common/net/buildbot/buildbot_unittest.py:
+
+2011-02-06 Maciej Stachowiak <mjs@apple.com>
+
+ Reviewed by Ryosuke Niwa.
+
+ Update test expectations for new core builder
+ https://bugs.webkit.org/show_bug.cgi?id=53904
+
+ * Scripts/webkitpy/common/net/buildbot/buildbot_unittest.py:
+
+2011-02-06 Maciej Stachowiak <mjs@apple.com>
+
+ Reviewed by David Levin.
+
+ Add WebKit2 test bot to core builders
+ https://bugs.webkit.org/show_bug.cgi?id=53901
+
+ * Scripts/webkitpy/common/net/buildbot/buildbot.py:
+
+2011-02-06 Ryosuke Niwa <rniwa@webkit.org>
+
+ Another unreviewed Chromium build fix.
+
+ * DumpRenderTree/chromium/LayoutTestController.cpp:
+ (LayoutTestController::pathToLocalResource):
+
+2011-02-06 Ryosuke Niwa <rniwa@webkit.org>
+
+ Unreviewed Chromium build fix.
+
+ * DumpRenderTree/chromium/LayoutTestController.cpp:
+ (LayoutTestController::pathToLocalResource):
+
+2011-02-06 Ryosuke Niwa <rniwa@webkit.org>
+
+ Reviewed by Darin Adler.
+
+ OwnArraryPtr.h uses deleteOwnedPtr but doesn’t include OwnPtrCommon.h
+ https://bugs.webkit.org/show_bug.cgi?id=52867
+
+ * DumpRenderTree/chromium/ImageDiff.cpp:
+ (Image::craeteFromStdin): Call adoptArrayPtr.
+
+2011-02-06 James Kozianski <koz@chromium.org>
+
+ Reviewed by Ojan Vafai.
+
+ Add classes for representing test outputs.
+ https://bugs.webkit.org/show_bug.cgi?id=52136
+
+ These classes will make it easier to write scripts that deal with test
+ outputs such as rebaselining and deduping scripts. The intent is that
+ eventually we will be have buildbot return TestOutputs for a
+ particular build which can be compared with TestOutputs derived from a
+ local LayoutTests directory.
+
+ * Scripts/webkitpy/common/net/testoutput.py: Added.
+ * Scripts/webkitpy/common/net/testoutput_unittest.py: Added.
+ * Scripts/webkitpy/common/net/testoutputset.py: Added.
+ * Scripts/webkitpy/common/net/testoutputset_unittest.py: Added.
+ * Scripts/webkitpy/common/system/zip_mock.py: Added.
+
+2011-02-06 Robert Hogan <robert@webkit.org>
+
+ Reviewed by Andreas Kling.
+
+ [Qt] Clear page's groupName even when not in DRT
+ https://bugs.webkit.org/show_bug.cgi?id=53874
+
+ * DumpRenderTree/qt/DumpRenderTreeQt.cpp:
+ (WebCore::DumpRenderTree::windowCloseRequested):
+
+2011-02-06 Patrick Gansterer <paroga@webkit.org>
+
+ Reviewed by Andreas Kling.
+
+ [CMake] Add dependencies for Visual Studio projects
+ https://bugs.webkit.org/show_bug.cgi?id=53773
+
+ Add a WebKit dependecy to WinCELauncher, so CMake can
+ generate the correct build order for the solution.
+
+ * CMakeListsWinCE.txt:
+
+2011-02-06 Andreas Kling <kling@webkit.org>
+
+ Reviewed by Antonio Gomes.
+
+ [Qt] MiniBrowser: Clean up handling of titleChanged() signal
+ https://bugs.webkit.org/show_bug.cgi?id=53869
+
+ * MiniBrowser/qt/BrowserView.cpp:
+ (BrowserView::BrowserView): Remove unnecessary titleChanged() handling.
+ * MiniBrowser/qt/BrowserWindow.cpp:
+ (BrowserWindow::BrowserWindow): Connect titleChanged() directly to setWindowTitle().
+ * MiniBrowser/qt/BrowserWindow.h:
+
+2011-02-06 Maciej Stachowiak <mjs@apple.com>
+
+ Reviewed by Dan Bernstein.
+
+ WebKitTestRunner needs layoutTestController.setWillSendRequestReturnsNull
+ https://bugs.webkit.org/show_bug.cgi?id=42690
+ <rdar://problem/8213851>
+
+ * WebKitTestRunner/InjectedBundle/Bindings/LayoutTestController.idl:
+ * WebKitTestRunner/InjectedBundle/InjectedBundlePage.cpp:
+ (WTR::InjectedBundlePage::willSendRequestForFrame):
+ * WebKitTestRunner/InjectedBundle/LayoutTestController.cpp:
+ (WTR::LayoutTestController::LayoutTestController):
+ * WebKitTestRunner/InjectedBundle/LayoutTestController.h:
+ (WTR::LayoutTestController::willSendRequestReturnsNull):
+ (WTR::LayoutTestController::setWillSendRequestReturnsNull):
+
+2011-02-05 Sheriff Bot <webkit.review.bot@gmail.com>
+
+ Unreviewed, rolling out r77720.
+ http://trac.webkit.org/changeset/77720
+ https://bugs.webkit.org/show_bug.cgi?id=53854
+
+ "Broke nrwt on Chromium win." (Requested by dglazkov|away on
+ #webkit).
+
+ * Scripts/webkitpy/common/system/executive.py:
+
+2011-02-05 Sheriff Bot <webkit.review.bot@gmail.com>
+
+ Unreviewed, rolling out r77725.
+ http://trac.webkit.org/changeset/77725
+ https://bugs.webkit.org/show_bug.cgi?id=53844
+
+ It broke Qt minimal build (Requested by Ossy_ on #webkit).
+
+ * QtTestBrowser/launcherwindow.cpp:
+ (LauncherWindow::createChrome):
+ * QtTestBrowser/launcherwindow.h:
+ (WindowOptions::WindowOptions):
+ * QtTestBrowser/main.cpp:
+ (LauncherApplication::handleUserOptions):
+
+2011-02-04 Martin Robinson <mrobinson@igalia.com>
+
+ Reviewed by Adam Barth.
+
+ [GTK] plugins/plugin-document-back-forward.html fails
+ https://bugs.webkit.org/show_bug.cgi?id=53833
+
+ Add the new "alert on load" functionality for the Unix version of the
+ test plugin. This functionality was originally introduced in r77706.
+
+ * DumpRenderTree/unix/TestNetscapePlugin/TestNetscapePlugin.cpp:
+ (webkit_test_plugin_new_instance): Add new plugin fuctionality.
+
+2011-02-04 Kundu Suchismita <suchi.kundu@nokia.com>
+
+ Reviewed by Andreas Kling.
+
+ Local Storage settings can be enable/disable from "Develop" menu
+ https://bugs.webkit.org/show_bug.cgi?id=52296
+
+ * QtTestBrowser/launcherwindow.cpp:
+ (LauncherWindow::createChrome):
+ (LauncherWindow::toggleLocalStorage):
+ (LauncherWindow::toggleOfflineStorageDatabase):
+ (LauncherWindow::toggleOfflineWebApplicationCache):
+ (LauncherWindow::setOfflineStorageDefaultQuota):
+ * QtTestBrowser/launcherwindow.h:
+ (WindowOptions::WindowOptions):
+ * QtTestBrowser/main.cpp:
+ (LauncherApplication::handleUserOptions):
+
+2011-02-04 Tony Chang <tony@chromium.org>
+
+ Reviewed by Eric Seidel.
+
+ get test-webkitpy running on win32 python
+ https://bugs.webkit.org/show_bug.cgi?id=53822
+
+ The test harness crashes with a WindowsError because it can't find
+ 'svn' when using subprocess.Popen. This gets us past the error
+ so we can see the failing tests on the Chromium Win Release Tests
+ bot.
+
+ * Scripts/webkitpy/common/system/executive.py:
+
+2011-02-04 Martin Robinson <mrobinson@igalia.com>
+
+ Reviewed by Gustavo Noronha Silva.
+
+ [GTK] fast/events/pagehide-timeout.html fails
+ https://bugs.webkit.org/show_bug.cgi?id=53771
+
+ Add knowledge of the document browser cache model the DRT. When resetting
+ WebKit settings to consistent values between tests, default to the document
+ browser cache model.
+
+ * DumpRenderTree/gtk/DumpRenderTree.cpp:
+ (resetDefaultsToConsistentValues): Reset the cache model to the document browser
+ cache model between tests.
+ * DumpRenderTree/gtk/LayoutTestControllerGtk.cpp:
+ (LayoutTestController::setCacheModel): An int value of 2 here corresponds to the
+ document browser cache model.
+
+2011-02-04 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ PluginDocuments don't create widgets for plugins on back/forward
+ https://bugs.webkit.org/show_bug.cgi?id=53474
+
+ Teach the test plugin how to call alert on load.
+
+ * DumpRenderTree/TestNetscapePlugIn/main.cpp:
+ (NPP_New):
+
+2011-02-04 Adam Roben <aroben@apple.com>
+
+ Add a test case for encode/decode of FormData/FormDataElement
+
+ If the fix made in r77401 is broken, this new test will crash.
+
+ Fixes <http://webkit.org/b/53616> <rdar://problem/8949883>.
+
+ Reviewed by Sam Weinig.
+
+ * TestWebKitAPI/Test.h: Moved the bulk of TEST_ASSERT into a new _TEST_ASSERT_HELPER macro.
+ Added a new TEST_ASSERT_RETURN macro that can be used in functions with a return value.
+
+ * TestWebKitAPI/Tests/WebKit2/RestoreSessionStateContainingFormData.cpp: Added.
+ (TestWebKitAPI::didFinishLoadForFrame): Record that the load is finished.
+ (TestWebKitAPI::setPageLoaderClient): Hook up the loader client.
+ (TestWebKitAPI::createSessionStateContainingFormData): Load simple-form.html, submit the
+ form, an return the session state data.
+ (TestWebKitAPI::TEST): Create some session state that contains form data from one WKPage,
+ and restore it into another WKPage.
+
+ * TestWebKitAPI/Tests/WebKit2/simple-form.html: Added.
+
+ * TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj:
+ * TestWebKitAPI/win/TestWebKitAPI.vcproj:
+ * TestWebKitAPI/win/copy-resources.cmd:
+ Added new files.
+
+2011-02-04 Adam Roben <aroben@apple.com>
+
+ Move code to run JavaScript tests into its own files
+
+ This will allow other tests to use this mechanism.
+
+ Fixes <http://webkit.org/b/53806> SpacebarScrolling should share its JavaScript-fu with the
+ world
+
+ Reviewed by Sam Weinig.
+
+ * TestWebKitAPI/JavaScriptTest.cpp: Added.
+ * TestWebKitAPI/JavaScriptTest.h: Added.
+ Moved code here...
+
+ * TestWebKitAPI/Tests/WebKit2/SpacebarScrolling.cpp: ...from here.
+
+ * TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj:
+ * TestWebKitAPI/win/TestWebKitAPI.vcproj:
+ Added the new files.
+
+2011-02-04 Dirk Pranke <dpranke@chromium.org>
+
+ Reviewed by Mihai Parparita.
+
+ merge test expectations for chromium, chromium-gpu. The
+ chromium-gpu port will no longer maintain its own
+ test expectations file.
+
+ Also add in a graphics_type() call on the port object to
+ determine what graphics type to use in the test configuration,
+ and log the configuration as a config setting.
+
+ https://bugs.webkit.org/show_bug.cgi?id=53562
+
+ * Scripts/webkitpy/layout_tests/port/base.py:
+ * Scripts/webkitpy/layout_tests/layout_package/test_runner.py:
+ * Scripts/webkitpy/layout_tests/port/chromium_gpu.py:
+ * Scripts/webkitpy/layout_tests/port/chromium_gpu_unittest.py:
+
+2011-02-04 Mikhail Naganov <mnaganov@chromium.org>
+
+ Reviewed by Pavel Feldman.
+
+ Web Inspector: fix processing Unicode literals from .js sources in check-inspector-strings.
+ https://bugs.webkit.org/show_bug.cgi?id=53781
+
+ * Scripts/check-inspector-strings:
+
+2011-02-04 Adam Roben <aroben@apple.com>
+
+ Include the crashing function in the link to a crash log on Mac
+
+ Fixes <http://webkit.org/b/53780> Crash log links in results.html should include the
+ function that crashed on Mac
+
+ Reviewed by David Kilzer.
+
+ * Scripts/old-run-webkit-tests:
+ (crashLocation): Moved all the Windows code inside an if instead of using an early return,
+ but didn't otherwise change it. Added an if for Mac that parses the crashing function out of
+ the crash log.
+
+2011-02-04 Adam Roben <aroben@apple.com>
+
+ Link to Mac crash logs from results.html
+
+ Fixes <http://webkit.org/b/14861> run-webkit-tests should link to Mac crash logs in
+ results.html
+
+ Reviewed by David Kilzer.
+
+ * Scripts/old-run-webkit-tests:
+ (captureSavedCrashLog): Added a case for Apple's Mac port. We get the crash log out of
+ ~/Library/Logs/CrashReporter, and wait for ReportCrash to exit before trying to get the log.
+
+2011-02-03 Maciej Stachowiak <mjs@apple.com>
+
+ Reviewed by Dan Bernstein.
+
+ WebKit2: Need WebKit2 equivalent of WebResourceLoadDelegate::willSendRequest in the Bundle
+ https://bugs.webkit.org/show_bug.cgi?id=52897
+ <rdar://problem/8898294>
+
+ * WebKitTestRunner/InjectedBundle/InjectedBundlePage.cpp:
+ (WTR::InjectedBundlePage::InjectedBundlePage):
+ (WTR::InjectedBundlePage::willSendRequestForFrame):
+ * WebKitTestRunner/InjectedBundle/InjectedBundlePage.h:
+
+2011-02-03 Ivan Krstić <ike@apple.com>
+
+ Unreviewed.
+
+ Adding myself to committers.py.
+
+ * Scripts/webkitpy/common/config/committers.py:
+
+2011-02-03 James Kozianski <koz@chromium.org>
+
+ Reviewed by Dimitri Glazkov.
+
+ Add navigator.registerProtocolHandler behind a flag.
+ https://bugs.webkit.org/show_bug.cgi?id=52609
+
+ * Scripts/build-webkit:
+
+2011-02-03 Hayato Ito <hayato@chromium.org>
+
+ Reviewed by Eric Seidel.
+
+ [NRWT] Remove TestArgs class, which is wrongly used.
+
+ https://bugs.webkit.org/show_bug.cgi?id=53063
+
+ * Scripts/webkitpy/layout_tests/layout_package/dump_render_tree_thread.py:
+ * Scripts/webkitpy/layout_tests/layout_package/single_test_runner.py:
+ * Scripts/webkitpy/layout_tests/test_types/image_diff.py:
+ * Scripts/webkitpy/layout_tests/test_types/test_type_base.py:
+ * Scripts/webkitpy/layout_tests/test_types/test_type_base_unittest.py:
+ * Scripts/webkitpy/layout_tests/test_types/text_diff.py:
+
+2011-02-03 Andrew Wason <rectalogic@rectalogic.com>
+
+ Reviewed by Kenneth Russell.
+
+ Change ENABLE_3D_CANVAS to ENABLE_WEBGL
+ https://bugs.webkit.org/show_bug.cgi?id=53714
+
+ * Scripts/build-webkit: change --3d-canvas build option
+ to set ENABLE_WEBGL
+
+2011-02-03 Hayato Ito <hayato@chromium.org>
+
+ Reviewed by Tony Chang.
+
+ [NRWT] Introduces Input/Output class used by base.Driver into port/base.py and
+ move _run_single_test() and _process_output() functions from
+ dump_render_tree_thread.py to a single_test_runner.py as an individual module.
+
+ This is clean up and acts as a preparation for elimination of test_types/*
+ classes. These classes will move to the single_test_runner module introduced
+ in this patch.
+
+ https://bugs.webkit.org/show_bug.cgi?id=53004
+
+ * Scripts/webkitpy/layout_tests/layout_package/dump_render_tree_thread.py:
+ * Scripts/webkitpy/layout_tests/layout_package/single_test_runner.py: Added.
+ * Scripts/webkitpy/layout_tests/layout_package/test_input.py:
+ * Scripts/webkitpy/layout_tests/layout_package/test_output.py: Removed.
+ * Scripts/webkitpy/layout_tests/port/base.py:
+ * Scripts/webkitpy/layout_tests/port/chromium.py:
+ * Scripts/webkitpy/layout_tests/port/dryrun.py:
+ * Scripts/webkitpy/layout_tests/port/test.py:
+ * Scripts/webkitpy/layout_tests/port/webkit.py:
+ * Scripts/webkitpy/layout_tests/test_types/image_diff.py:
+ * Scripts/webkitpy/layout_tests/test_types/test_type_base.py:
+ * Scripts/webkitpy/layout_tests/test_types/text_diff.py:
+
+2011-02-03 Dirk Pranke <dpranke@chromium.org>
+
+ Unreviewed, build fix.
+
+ Delete a line that was accidentally missed in r77586; without it
+ there is still a race between the two threads.
+
+ https://bugs.webkit.org/show_bug.cgi?id=51572
+
+ * Scripts/webkitpy/layout_tests/layout_package/message_broker_unittest.py:
+
+2011-02-03 Dirk Pranke <dpranke@chromium.org>
+
+ Reviewed by Tony Chang.
+
+ nrwt: handle "broken pipe" notifications from DRT more cleanly.
+
+ https://bugs.webkit.org/show_bug.cgi?id=52927
+
+ * Scripts/webkitpy/layout_tests/port/server_process.py:
+ * Scripts/webkitpy/layout_tests/port/server_process_unittest.py:
+
+2011-02-03 Dirk Pranke <dpranke@chromium.org>
+
+ Reviewed by Kenneth Russell.
+
+ Update, resubmit change to bug 51572. I think the race that was
+ fixed in r76703 caused the hang that caused us to roll this
+ patch out before, so I'd like to try again.
+
+ https://bugs.webkit.org/show_bug.cgi?id=51572
+
+ * Scripts/webkitpy/layout_tests/layout_package/message_broker.py:
+ * Scripts/webkitpy/layout_tests/layout_package/message_broker_unittest.py:
+
+2011-02-03 Daniel Cheng <dcheng@chromium.org>
+
+ Unreviewed.
+
+ Adding myself to committers.py.
+
+ * Scripts/webkitpy/common/config/committers.py:
+
+2011-02-03 Adam Roben <aroben@apple.com>
+
+ Include the crashing function in the link to a crash log
+
+ Fixes <http://webkit.org/b/53739> Crash log links in results.html should include the
+ function that crashed
+
+ Reviewed by David Kilzer.
+
+ * Scripts/old-run-webkit-tests:
+ (crashLocation): Added. Returns the location of the crash.
+ (linksForErrorTest): Include the crash location in the link text for the crash log, if one
+ could be determined.
+
+2011-02-03 Dirk Pranke <dpranke@chromium.org>
+
+ Unreviewed, build fix.
+
+ Actually make the changes suggested by Mihai in his review
+ of bug 53720 :(
+
+ https://bugs.webkit.org/show_bug.cgi?id=53720
+
+ * Scripts/webkitpy/layout_tests/port/test_files.py:
+ * Scripts/webkitpy/layout_tests/port/test_files_unittest.py:
+
+2011-02-03 Dirk Pranke <dpranke@chromium.org>
+
+ Reviewed by Mihai Parparita.
+
+ new-run-webkit-tests: Fix bug introduced in r77434 that was
+ causing us to run the canvas GPU tests on the Mac GPU port. This
+ bug revealed that we were not setting the port.name() field
+ properly in many cases, so I've cleaned up all of that code, and
+ removed a few comments about "version-specific" GPU ports that
+ don't exist and just confused things.
+
+ Testing also revealed that port.abspath_for_test() wasn't
+ normalizing paths on Windows properly, so I fixed that as well.
+
+ https://bugs.webkit.org/show_bug.cgi?id=53719
+
+ * Scripts/webkitpy/layout_tests/port/base.py:
+ * Scripts/webkitpy/layout_tests/port/chromium_gpu.py:
+ * Scripts/webkitpy/layout_tests/port/chromium_gpu_unittest.py:
+
+2011-02-03 Dirk Pranke <dpranke@chromium.org>
+
+ Reviewed by Mihai Parparita.
+
+ new-run-webkit-tests: fix normalization of paths on windows when gathering files
+
+ r77434 introduced a bug that was causing the test expectations
+ for the GPU ports to not be treated properly. It turns out that
+ when we gathered the list of test files on Windows, we would
+ return paths of the form "c:\LayoutTests/fast/canvas", and the
+ mixture of backslashes and forward slashes was confusing things.
+
+ This patch normalizes all of the filenames returned from
+ test_files.find(), and adds better tests for this (fixing a
+ couple of other bugs found in the meantime).
+
+ https://bugs.webkit.org/show_bug.cgi?id=53720
+
+ * Scripts/webkitpy/layout_tests/port/test.py:
+ * Scripts/webkitpy/layout_tests/port/test_files.py:
+ * Scripts/webkitpy/layout_tests/port/test_files_unittest.py:
+
+2011-02-03 Adam Roben <aroben@apple.com>
+
+ Add links to Windows crash logs in results.html
+
+ Fixes <http://webkit.org/b/53718> run-webkit-tests should link to Windows crash logs in
+ results.html
+
+ Reviewed by David Kilzer.
+
+ * Scripts/old-run-webkit-tests:
+ (top level): Added $crashLogTag and $windowsCrashLogFilePrefix (which came from
+ createDebuggerCommandFile).
+ (testCrashedOrTimedOut): If the test crashed, capture any saved crash log after the dump
+ tool has exited.
+ (captureSavedCrashLog): Added. Finds the crash log for the test that just crashed and moves
+ it into the test results directory tree. Only implemented for Cygwin currently.
+ (findNewestFileMatchingGlob): Added. Does what it says.
+ (htmlForResultsSection): Only link to files that exist.
+ (linksForErrorTest): Add a link to the crash log.
+ (deleteExpectedAndActualResults): Delete any old crash log for this test.
+ (createDebuggerCommandFile): Use the new $windowsCrashLogFilePrefix constant instead of
+ hardcoding it here.
+
+2011-02-03 Adam Roben <aroben@apple.com>
+
+ Tell the debugger the path to the WebKit source tree when saving a crash log
+
+ This allows the debugger to include the crashing line of code in the log.
+
+ Fixes <http://webkit.org/b/53678> Crash logs from buildslaves don't show the crashing line
+ of code
+
+ Reviewed by Sam Weinig.
+
+ * Scripts/old-run-webkit-tests:
+ (createDebuggerCommandFile): Added. Saves commands that we'd like the debugger to run to a
+ file and returns the path to that file. The commands we pass came from
+ setUpWindowsCrashLogSaving, but I've added a .srcpath command to tell the debugger where the
+ WebKit source code lives.
+ (setUpWindowsCrashLogSaving): Instead of specifying the commands directly on the command
+ line using -c, save them to a file and specify the path to that file using -cf. This works
+ around what is presumably a bug in Windows's command line parsing, where having multiple
+ quoted paths in the debugger commands causes the post-mortem debugger not to be invoked at
+ all. Also pulled the options we pass to the debugger out into a list that is then join()ed
+ together to make them easier to modify in the future.
+
+2011-02-02 Sam Weinig <sam@webkit.org>
+
+ Reviewed by Anders Carlsson.
+
+ Add notification of the end of a rubber band.
+ <rdar://problem/8940648>
+
+ * MiniBrowser/mac/BrowserWindowController.m:
+ (-[BrowserWindowController awakeFromNib]):
+ * WebKitTestRunner/TestController.cpp:
+ (WTR::TestController::createOtherPage):
+ (WTR::TestController::initialize):
+ Stub out the new WKUIClient function.
+
+2011-02-03 Gabor Rapcsanyi <rgabor@webkit.org>
+
+ Unreviewed.
+
+ Adding myself to committers.py.
+
+ * Scripts/webkitpy/common/config/committers.py:
+
+2011-02-03 Balazs Kelemen <kbalazs@webkit.org>
+
+ Reviewed by Csaba Osztrogonác.
+
+ [Qt][WK2] MiniBrowser's window size should be 800x600
+ https://bugs.webkit.org/show_bug.cgi?id=53670
+
+ Make layout test failure debugging easier.
+ * MiniBrowser/qt/BrowserWindow.cpp:
+ (BrowserWindow::BrowserWindow):
+
+2011-02-02 Andy Estes <aestes@apple.com>
+
+ Reviewed by Mark Rowe.
+
+ 'update-webkit' should handle OpenSource and Internal using different
+ VCSs.
+
+ * Scripts/update-webkit: Re-check the VCS type when updating Apple's
+ Internal directory.
+
+2011-02-02 Dirk Pranke <dpranke@chromium.org>
+
+ Reviewed by Mihai Parparita.
+
+ new-run-webkit-tests: hardcode the directories to scan for tests
+ for GPU bots instead of SKIPping them. See bug 53562 for some
+ context, but we will now hard-code the list of directories to
+ use by default instead of skipping over directories in the
+ expectations file. We do this so that we will be able to merge
+ the expectations files without getting conflicting SKIP
+ directives. Note that this change will reduce the # of tests
+ being run on the Mac GPU bots, because we're accidentally
+ including some today.
+
+ https://bugs.webkit.org/show_bug.cgi?id=53631
+
+ * Scripts/webkitpy/layout_tests/port/base.py:
+ * Scripts/webkitpy/layout_tests/port/chromium_gpu.py:
+ * Scripts/webkitpy/layout_tests/port/chromium_gpu_unittest.py:
+
+2011-02-02 Sam Weinig <sam@webkit.org>
+
+ Reviewed by Beth Dakin.
+
+ Add ChromeClient function to paint custom overhang areas.
+ https://bugs.webkit.org/show_bug.cgi?id=53639
+
+ * WebKitTestRunner/InjectedBundle/InjectedBundlePage.cpp:
+ (WTR::InjectedBundlePage::InjectedBundlePage):
+ Stub out new callback.
+
+2011-02-02 Dirk Pranke <dpranke@chromium.org>
+
+ Reviewed by Tony Chang.
+
+ new-run-webkit-tests: support chromium code paths in mock_drt
+
+ https://bugs.webkit.org/show_bug.cgi?id=53471
+
+ * Scripts/webkitpy/layout_tests/port/mock_drt.py:
+ * Scripts/webkitpy/layout_tests/port/mock_drt_unittest.py:
+
+2011-02-02 Adam Klein <adamk@chromium.org>
+
+ Reviewed by Tony Chang.
+
+ Update new-run-webkit-tests --chromium to put output under Source/...
+ https://bugs.webkit.org/show_bug.cgi?id=53612
+
+ * BuildSlaveSupport/test-result-archive:
+ * Scripts/webkitpy/layout_tests/port/chromium.py:
+
+2011-01-28 Tony Chang <tony@chromium.org>
+
+ Reviewed by Eric Seidel.
+
+ [chromium] remove --use-test-shell from NRWT
+ https://bugs.webkit.org/show_bug.cgi?id=53346
+
+ I've already started removing some of the bindings like eventSender so
+ this already doesn't work isn't useful. Also updated some comments to
+ refer to DRT instead of test_shell.
+
+ * Scripts/webkitpy/layout_tests/layout_package/test_expectations.py:
+ * Scripts/webkitpy/layout_tests/port/chromium.py:
+ * Scripts/webkitpy/layout_tests/port/chromium_linux.py:
+ * Scripts/webkitpy/layout_tests/port/chromium_mac.py:
+ * Scripts/webkitpy/layout_tests/port/chromium_unittest.py:
+ * Scripts/webkitpy/layout_tests/port/chromium_win.py:
+ * Scripts/webkitpy/layout_tests/run_webkit_tests.py:
+ * Scripts/webkitpy/layout_tests/test_types/text_diff.py:
+
+2011-02-02 Steve Lacey <sjl@chromium.org>
+
+ Reviewed by Eric Carlson.
+
+ Implement basic media statistics on media elements.
+ https://bugs.webkit.org/show_bug.cgi?id=53322
+
+ * Scripts/build-webkit:
+
+2011-02-02 Kevin Ollivier <kevino@theolliviers.com>
+
+ [wx] Build fixes for wxWebKit.
+
+ * DumpRenderTree/wx/LayoutTestControllerWx.cpp:
+ (LayoutTestController::setSerializeHTTPLoads):
+ * wx/browser/wscript:
+ * wx/build/build_utils.py:
+ * wx/build/settings.py:
+
+2011-02-01 Dirk Pranke <dpranke@chromium.org>
+
+ Reviewed by Mihai Parparita.
+
+ new-run-webkit-tests: stop skipping so many tests
+
+ r77163 introduced a regression where we weren't resetting test
+ expectations properly and were skipping too many tests as a
+ result. This patch fixes that and adds a test for it.
+
+ https://bugs.webkit.org/show_bug.cgi?id=53551
+
+ * Scripts/webkitpy/layout_tests/layout_package/test_expectations.py:
+ * Scripts/webkitpy/layout_tests/layout_package/test_expectations_unittest.py:
+
+2011-02-01 Dirk Pranke <dpranke@chromium.org>
+
+ Reviewed by Tony Chang.
+
+ new-run-webkit-tests: add first stub of test_runner2. This
+ will add support for the 'inline', 'threads', and 'processes'
+ flags to --worker-model, but for now the implementatios just
+ fall back on the old ones.
+
+ https://bugs.webkit.org/show_bug.cgi?id=53157
+
+ * Scripts/webkitpy/layout_tests/layout_package/test_runner2.py:
+ * Scripts/webkitpy/layout_tests/run_webkit_tests_unittest.py:
+
+2011-02-01 Mihai Parparita <mihaip@chromium.org>
+
+ Reviewed by James Robinson.
+
+ [Chromium] run-chromium-webkit-unit-tests looks for binaries in the wrong place
+ https://bugs.webkit.org/show_bug.cgi?id=53522
+
+ * Scripts/run-chromium-webkit-unit-tests:
+
+2011-02-01 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Mihai Parparita.
+
+ Using Control-C to cancel webkit-patch or other python tools causes
+ unpleasant traceback console spew
+ https://bugs.webkit.org/show_bug.cgi?id=53462
+
+ Catch the exception and don't print the stack trace.
+
+ * Scripts/webkit-patch:
+
+2011-02-01 Scott Cameron <sccameron@rim.com>
+
+ Reviewed by Daniel Bates.
+
+ Use Windows format for MinGW HTTPD path.
+ https://bugs.webkit.org/show_bug.cgi?id=53503
+
+ * Scripts/webkitperl/httpd.pm:
+ - Use single-quotes around MySys value for $httpdPath in getHTTPDPath()
+ so that we don't have to escape the space characters in the path. Also,
+ changed path to Windows-style path and removed FIXME comment.
+
+2011-02-01 Balazs Kelemen <kbalazs@webkit.org>
+
+ Reviewed by Andreas Kling.
+
+ [Qt][WK2] Add a way to use shared process model in MiniBrowser
+ https://bugs.webkit.org/show_bug.cgi?id=53090
+
+ * MiniBrowser/qt/BrowserView.cpp:
+ (BrowserView::BrowserView): Removed the m_context member.
+ From now the context is guaranteed to be non-null and we
+ don't need to store that in the object.
+ * MiniBrowser/qt/BrowserView.h:
+ * MiniBrowser/qt/BrowserWindow.cpp:
+ Added static bool to determine that new windows need to be
+ created with their own context or not. Use the same context
+ and web process by default to be inilne with the other ports.
+ (BrowserWindow::BrowserWindow):
+ (BrowserWindow::newWindow):
+ * MiniBrowser/qt/BrowserWindow.h:
+ * MiniBrowser/qt/main.cpp:
+ (main): Added command line switch to be able to use the
+ non-shared process model. Simplify the handling of the command line
+ switches a little bit.
+
+2011-02-01 Zoltan Horvath <zoltan@webkit.org>
+
+ Reviewed by Andreas Kling.
+
+ [Qt] Add Window menu and Toggle FullScreen action to MiniBrowser.
+ https://bugs.webkit.org/show_bug.cgi?id=53491
+
+ * MiniBrowser/qt/BrowserWindow.cpp:
+ (BrowserWindow::BrowserWindow):
+ (BrowserWindow::toggleFullScreenMode):
+ * MiniBrowser/qt/BrowserWindow.h:
+
+2011-02-01 Zoltan Horvath <zoltan@webkit.org>
+
+ Reviewed by Andreas Kling.
+
+ [Qt] Add Toggle Frame Flattening, Auto Load Images and Disable JavaScript actions to MiniBrowser.
+ https://bugs.webkit.org/show_bug.cgi?id=53489
+
+ Add Toggle Frame Flattening action to Develop menu. Add Auto Load Images and Disable JavaScript actions
+ to Settings menu.
+
+ * MiniBrowser/qt/BrowserWindow.cpp:
+ (BrowserWindow::BrowserWindow):
+ (BrowserWindow::toggleFrameFlattening):
+ (BrowserWindow::toggleDisableJavaScript):
+ (BrowserWindow::toggleAutoLoadImages):
+ * MiniBrowser/qt/BrowserWindow.h:
+
+2011-01-31 Mihai Parparita <mihaip@chromium.org>
+
+ Reviewed by Tony Chang.
+
+ [Chromium] Switch chromium-mac to use ChromiumDriver
+ https://bugs.webkit.org/show_bug.cgi?id=53461
+
+ For the sake of consistency with the other Chromium platforms (and so
+ that chromium-mac picks up special flags like --enable-hardware-gpu),
+ switch chromium-mac from the WebKitDriver to ChromiumDriver.
+
+ * Scripts/webkitpy/layout_tests/port/chromium.py:
+
+2011-01-31 Dirk Pranke <dpranke@chromium.org>
+
+ Reviewed by Mihai Parparita.
+
+ The current modifier parsing code in test_expectations is
+ fragile and hard-coded, so it's not easy to understand the logic
+ or easily add new types of modifiers (like GPU vs. CPU testing
+ for graphics tests, or 32-bit vs. 64-bit differences).
+
+ This is the first of two patches that will add in more generic
+ support and then eliminate the GPU-specific test expectations
+ files for Chromium.
+
+ This patch adds two standalone objects for handling modifiers. The
+ rules for interpreting modifiers, precedence, and conflicts are
+ given in the docstring to the ModifierMatcher class, which
+ returns ModifierMatchResult objects.
+
+ This patch also adds routines to the Port interface and a
+ default set of values in the base object, in order to obtain the
+ values needed on a given test run. These values are then passed
+ to the expectation parser. This also allows us to clean up the
+ logic used to lint all of the different configurations in a
+ single test_expectations.txt file.
+
+ The next patch will merge in the separate GPU expectations file.
+
+ https://bugs.webkit.org/show_bug.cgi?id=51222
+
+ * Scripts/webkitpy/layout_tests/layout_package/printing_unittest.py:
+ * Scripts/webkitpy/layout_tests/layout_package/test_expectations.py:
+ * Scripts/webkitpy/layout_tests/layout_package/test_expectations_unittest.py:
+ * Scripts/webkitpy/layout_tests/layout_package/test_runner.py:
+ * Scripts/webkitpy/layout_tests/port/base.py:
+ * Scripts/webkitpy/layout_tests/port/base_unittest.py:
+ * Scripts/webkitpy/layout_tests/port/chromium.py:
+ * Scripts/webkitpy/layout_tests/port/port_testcase.py:
+ * Scripts/webkitpy/layout_tests/port/test.py:
+ * Scripts/webkitpy/layout_tests/port/webkit.py:
+ * Scripts/webkitpy/layout_tests/rebaseline_chromium_webkit_tests.py:
+ * Scripts/webkitpy/layout_tests/rebaseline_chromium_webkit_tests_unittest.py:
+ * Scripts/webkitpy/layout_tests/run_webkit_tests.py:
+ * Tools/Scripts/webkitpy/style/checkers/test_expectations.py:
+ * Tools/Scripts/webkitpy/style/checkers/test_expectations_unittest.py:
+
+2011-01-31 Scott Cameron <sccameron@rim.com>
+
+ Reviewed by Daniel Bates.
+
+ update run-webkit-httpd to be able to launch Apache2.2 in a MSYS environment
+ https://bugs.webkit.org/show_bug.cgi?id=50036
+
+ This will add an Apache2.2 configuration file and modifies scripts to allow
+ running an httpd server in an MSYS environment.
+
+ The default Apache2.2 installation path has been preserved and PHP5 modules disabled
+ in order to allow for simple installation/execution. Simply install the latest
+ Apache2.2 version with OpenSSL from http://httpd.apache.org/download.cgi#apache22 to
+ be able to execute run-webkit-httpd.
+
+
+ * Scripts/run-webkit-httpd:
+ * Scripts/webkitperl/httpd.pm:
+
+2011-01-31 Tony Chang <tony@chromium.org>
+
+ Reviewed by Eric Seidel.
+
+ mac DRT should report RTL scroll offset relative to top right corner
+ https://bugs.webkit.org/show_bug.cgi?id=53324
+
+ * DumpRenderTree/mac/DumpRenderTree.mm:
+ (dumpFrameScrollPosition):
+
+2011-01-31 Zoltan Horvath <zoltan@webkit.org>
+
+ Reviewed by Andreas Kling.
+
+ [Qt] Add Take Screen Shot action to MiniBrowser
+ https://bugs.webkit.org/show_bug.cgi?id=53422
+
+ Add Take Screen Shot action to MiniBrowser's view menu.
+
+ * MiniBrowser/qt/BrowserWindow.cpp:
+ (BrowserWindow::BrowserWindow):
+ (BrowserWindow::screenshot):
+ * MiniBrowser/qt/BrowserWindow.h:
+
+2011-01-31 Gustavo Noronha Silva <gustavo.noronha@collabora.co.uk>
+
+ Reviewed by Xan Lopez.
+
+ [GTK] REGRESSION: http/tests/media/video-{cookie,referer}.html failing
+ https://bugs.webkit.org/show_bug.cgi?id=53379
+
+ Remove left over #ifdef's. I thought all of the conditional code
+ had been freed from the condition, but I forgot to check DRT.
+
+ * DumpRenderTree/gtk/DumpRenderTree.cpp:
+ (resetDefaultsToConsistentValues):
+ * DumpRenderTree/gtk/LayoutTestControllerGtk.cpp:
+ (LayoutTestController::setAlwaysAcceptCookies):
+
+2011-01-30 Dirk Pranke <dpranke@chromium.org>
+
+ Unreviewed, build fix.
+
+ Fix regression introduced in r77093 - path.rsplit() doesn't
+ take keyword arguments.
+
+ https://bugs.webkit.org/show_bug.cgi?id=53326
+
+ * Scripts/webkitpy/common/system/filesystem_mock.py:
+
+2011-01-30 Dirk Pranke <dpranke@chromium.org>
+
+ Reviewed by Mihai Parparita.
+
+ Add more unit tests for rebaseline-chromium-webkit-tests. This
+ change involves restructuring a bunch of r-c-w-t code to make it
+ more testable as well. We also add wrapper classes for handling
+ testing zip files and fetching URLs.
+
+ https://bugs.webkit.org/show_bug.cgi?id=53040
+
+ * Scripts/webkitpy/common/system/urlfetcher.py:
+ * Scripts/webkitpy/common/system/urlfetcher_mock.py:
+ * Scripts/webkitpy/common/system/zipfileset_mock.py:
+ * Scripts/webkitpy/layout_tests/rebaseline_chromium_webkit_tests.py:
+ * Scripts/webkitpy/layout_tests/rebaseline_chromium_webkit_tests_unittest.py:
+ * Scripts/webkitpy/tool/mocktool.py:
+
+2011-01-30 Dirk Pranke <dpranke@chromium.org>
+
+ Reviewed by Eric Seidel.
+
+ Clean up of the filesystem-related modules used in webkitpy.
+ I've added relpath() to the filesystem interface, modified
+ ospath.relpath() so that it could work with the filesystem
+ interface, and modified the fileset* routines to use the
+ filesystem interface consistently.
+
+ This patch also adds a close() routine to the fileset routines
+ to indicate that the caller is done with the fileset. This
+ allows zipfileset to clean up after itself when it creates
+ tempfiles to store downloads.
+
+ https://bugs.webkit.org/show_bug.cgi?id=53326
+
+ * Scripts/webkitpy/common/system/directoryfileset.py:
+ * Scripts/webkitpy/common/system/fileset.py:
+ * Scripts/webkitpy/common/system/filesystem.py:
+ * Scripts/webkitpy/common/system/filesystem_mock.py:
+ * Scripts/webkitpy/common/system/filesystem_unittest.py:
+ * Scripts/webkitpy/common/system/ospath.py:
+ * Scripts/webkitpy/common/system/zipfileset.py:
+ * Scripts/webkitpy/common/system/zipfileset_unittest.py:
+
+2011-01-30 Balazs Kelemen <kbalazs@webkit.org>
+
+ Reviewed by Csaba Osztrogonác.
+
+ [Qt][WK2]REGRESSION (r76991): Fix build errors
+ https://bugs.webkit.org/show_bug.cgi?id=53400
+
+ Revert the temporary build fix (http://trac.webkit.org/changeset/77088)
+ and remove WebKit2Prefix.h from the build.
+ * MiniBrowser/qt/MiniBrowser.pro:
+
+2011-01-30 Csaba Osztrogonác <ossy@webkit.org>
+
+ Unreviewed.
+
+ [Qt][WK2] Buildfix.
+
+ * MiniBrowser/qt/MiniBrowser.pro:
+
+2011-01-28 Simon Fraser <simon.fraser@apple.com>
+
+ Reviewed by Adam Roben.
+
+ define NOMINMAX when building ImageDiff, as we do elsewhere.
+
+ Add various clampToInt() methods to MathExtras.h
+ https://bugs.webkit.org/show_bug.cgi?id=52910
+
+ * DumpRenderTree/win/ImageDiffCommon.vsprops:
+
+2011-01-28 Maciej Stachowiak <mjs@apple.com>
+
+ Reviewed by Darin Adler.
+
+ WebKitTestRunner needs layoutTestController.setPOSIXLocale
+ https://bugs.webkit.org/show_bug.cgi?id=42682
+
+ * WebKitTestRunner/InjectedBundle/Bindings/LayoutTestController.idl:
+ * WebKitTestRunner/InjectedBundle/InjectedBundle.cpp:
+ (WTR::InjectedBundle::resetLocalSettings):
+ (WTR::InjectedBundle::didReceiveMessage):
+ * WebKitTestRunner/InjectedBundle/InjectedBundle.h:
+ * WebKitTestRunner/InjectedBundle/LayoutTestController.cpp:
+ (WTR::LayoutTestController::setPOSIXLocale):
+ * WebKitTestRunner/InjectedBundle/LayoutTestController.h:
+
+2011-01-28 Dirk Pranke <dpranke@chromium.org>
+
+ Reviewed by Mihai Parparita.
+
+ test-webkitpy: fix webkitpy.layout_tests.port.mac_unittest.MacTest.test_skipped_file_paths
+
+ This patch re-enables this test and changes it to
+ handle all of the mac platform versions, not just the one
+ it is running on.
+
+ https://bugs.webkit.org/show_bug.cgi?id=53356
+
+ * Scripts/webkitpy/layout_tests/port/mac_unittest.py:
+
+2011-01-28 Dirk Pranke <dpranke@chromium.org>
+
+ Unreviewed, build fix.
+
+ Take two. The fix in 77023 didn't work, because we were
+ still calling path.abspath_to_uri, which calls _cygpath under
+ the covers, and it appears the cygpath on the bots does
+ something different than it does on my machine. This patch
+ removes the calls to path.abspath_to_uri, so it should be safe.
+ If it doesn't work, I'll roll it out along with r76982 and 77023.
+
+ https://bugs.webkit.org/show_bug.cgi?id=53126
+
+ * Scripts/webkitpy/layout_tests/port/test.py:
+
+2011-01-28 David Kilzer <ddkilzer@apple.com>
+
+ <rdar://problem/8930699> build-webkit gives a bogus warning with newer versions of Xcode
+ <http://webkit.org/b/53353>
+
+ Reviewed by Mark Rowe.
+
+ * Scripts/webkitdirs.pm:
+ (checkRequiredSystemConfig): Check the Xcode marketing version
+ in addition to the DevCoreTools build version before complaining
+ about an old version of Xcode. Also make the Mac OS X version
+ check use Perl's built-in version string comparitor.
+
+2011-01-28 Dirk Pranke <dpranke@chromium.org>
+
+ Unreviewed, build fix.
+
+ Work around breakage on Win 7 Release bot caused by r76982
+ and the fact that windows ports use "file:////" instead of
+ "file:///". Ideally the test code should be isolated from
+ this, but it isn't yet. Will fix properly in a bit.
+
+ * Scripts/webkitpy/layout_tests/port/mock_drt_unittest.py:
+
+2011-01-28 Dirk Pranke <dpranke@chromium.org>
+
+ Reviewed by Tony Chang.
+
+ new-run-webkit-tests: change worker model values to
+ "old-inline", "old-threads" in preparation for test_runner2 /
+ multiprocessing changes.
+
+ https://bugs.webkit.org/show_bug.cgi?id=53156
+
+ * Scripts/webkitpy/layout_tests/layout_package/test_runner.py:
+ * Scripts/webkitpy/layout_tests/port/base.py:
+ * Scripts/webkitpy/layout_tests/port/chromium_mac.py:
+ * Scripts/webkitpy/layout_tests/port/mac.py:
+ * Scripts/webkitpy/layout_tests/run_webkit_tests.py:
+
+2011-01-28 Dirk Pranke <dpranke@chromium.org>
+
+ Reviewed by Tony Chang.
+
+ committers.py - add an IRC nickname for dpranke
+ https://bugs.webkit.org/show_bug.cgi?id=53335
+
+ * Scripts/webkitpy/common/config/committers.py:
+
+2011-01-28 Dirk Pranke <dpranke@chromium.org>
+
+ Reviewed by Tony Chang.
+
+ new-run-webkit-tests: add a "mock DRT" port implementation
+ and a separate class that emulates what we expect the
+ DumpRenderTree behavior to be.
+
+ This will eventually replace port/dryrun.py and allow us to get
+ better test coverage of the new-run-webkit-tests code as well as
+ a reference for what new-run-webkit-tests expects from DRT.
+
+ This is the first attempt at this, and it is pretty bare-boned. It
+ really only has been tested on the 'mac' port (and a little on
+ the 'chromium-mac' port.
+
+ https://bugs.webkit.org/show_bug.cgi?id=53126
+
+ * Scripts/webkitpy/common/system/filesystem_mock.py:
+ * Scripts/webkitpy/layout_tests/port/dryrun.py:
+ * Scripts/webkitpy/layout_tests/port/factory.py:
+ * Scripts/webkitpy/layout_tests/port/mock_drt.py: Added.
+ * Scripts/webkitpy/layout_tests/port/mock_drt_unittest.py: Added.
+ * Scripts/webkitpy/layout_tests/port/test.py:
+
+2011-01-28 Pratik Solanki <psolanki@apple.com>
+
+ Unreviewed. Removing .swp file checked in by mistake.
+
+ * Scripts/.webkitdirs.pm.swp: Removed.
+
+2011-01-28 Pratik Solanki <psolanki@apple.com>
+
+ Reviewed by David Kilzer.
+
+ Space not necessary for undefined feature
+ https://bugs.webkit.org/show_bug.cgi?id=53317
+
+ * Scripts/build-webkit:
+
+2011-01-28 Chang Shu <chang.shu@nokia.com>
+
+ Reviewed by Andreas Kling.
+
+ Reset NetworkAccessManager to clean up credentials from previous tests.
+ This change causes no performance overhead either.
+ https://bugs.webkit.org/show_bug.cgi?id=36688
+
+ * DumpRenderTree/qt/DumpRenderTreeQt.cpp:
+ (WebCore::DumpRenderTree::resetToConsistentStateBeforeTesting):
+ (WebCore::DumpRenderTree::open):
+ * DumpRenderTree/qt/DumpRenderTreeQt.h:
+
+2011-01-28 Zoltan Horvath <zoltan@webkit.org>
+
+ Reviewed by Andreas Kling.
+
+ [Qt] Add Zoom Text Only action to MiniBrowser
+ https://bugs.webkit.org/show_bug.cgi?id=53297
+
+ Add Zoom Text Only action to MiniBrowser's view menu, change zoom levels to avoid unnecessary divides.
+
+ * MiniBrowser/qt/BrowserWindow.cpp:
+ (BrowserWindow::BrowserWindow):
+ (BrowserWindow::zoomIn):
+ (BrowserWindow::zoomOut):
+ (BrowserWindow::resetZoom):
+ (BrowserWindow::toggleZoomTextOnly):
+ (BrowserWindow::applyZoom):
+ * MiniBrowser/qt/BrowserWindow.h:
+
+2011-01-28 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ Add webkit-patch roll-chromium-deps
+ https://bugs.webkit.org/show_bug.cgi?id=53288
+
+ This command updates the Source/WebKit/chromium/DEPS file with the
+ last-known good revision of Chromium (or a revision specified on the
+ command line). I'd eventually like to turn this into a SheriffBot
+ command, but this is the first step.
+
+ This patch somewhat sprawled because I needed to move a bunch of code
+ out of ChangeLog that should never have been there in the first place.
+ Also, I had to fix a bug in MockUser in order to test the new command.
+
+ * Scripts/webkitpy/common/checkout/api.py:
+ * Scripts/webkitpy/common/checkout/changelog.py:
+ * Scripts/webkitpy/common/checkout/changelog_unittest.py:
+ * Scripts/webkitpy/common/checkout/deps.py: Added.
+ * Scripts/webkitpy/common/config/urls.py:
+ * Scripts/webkitpy/tool/commands/__init__.py:
+ * Scripts/webkitpy/tool/commands/download_unittest.py:
+ * Scripts/webkitpy/tool/commands/roll.py: Added.
+ * Scripts/webkitpy/tool/commands/roll_unittest.py: Added.
+ * Scripts/webkitpy/tool/commands/upload_unittest.py:
+ * Scripts/webkitpy/tool/mocktool.py:
+ * Scripts/webkitpy/tool/steps/__init__.py:
+ * Scripts/webkitpy/tool/steps/preparechangelogfordepsroll.py: Added.
+ * Scripts/webkitpy/tool/steps/preparechangelogforrevert.py:
+ * Scripts/webkitpy/tool/steps/preparechangelogforrevert_unittest.py: Added.
+ * Scripts/webkitpy/tool/steps/suggestreviewers_unittest.py:
+ * Scripts/webkitpy/tool/steps/updatechromiumdeps.py: Added.
+ * Scripts/webkitpy/tool/steps/validatechangelogs_unittest.py:
+
+2011-01-27 Greg Coletta <greg.coletta@nokia.com>
+
+ Reviewed by Laszlo Gombos.
+
+ Get rid of prefix header dependency for WebKit2 build system
+ https://bugs.webkit.org/show_bug.cgi?id=50174
+
+ Change the style checker so that it enforces config.h include for
+ WebKit2.
+
+ * Scripts/webkitpy/style/checker.py:
+
+2011-01-27 Maciej Stachowiak <mjs@apple.com>
+
+ Reviewed by Darin Adler.
+
+ execCommand("Paste") doesn't work in WebKitTestRunner
+ https://bugs.webkit.org/show_bug.cgi?id=52785
+
+ Enable both of the settings needed to allow paste.
+
+ * WebKitTestRunner/TestController.cpp:
+ (WTR::TestController::resetStateToConsistentValues):
+
+2011-01-27 Jacob Dinu <dinu.jacob@nokia.com>
+
+ Reviewed by Andreas Kling.
+
+ [Qt] QtTestBrowser: User input lost when toggling use of QGraphicsView
+ https://bugs.webkit.org/show_bug.cgi?id=48440
+
+ Preserve user input when toggling use of QGraphicsView
+
+ * QtTestBrowser/launcherwindow.cpp:
+ (LauncherWindow::initializeView):
+ (LauncherWindow::loadFinished):
+ * QtTestBrowser/launcherwindow.h:
+ * QtTestBrowser/mainwindow.cpp:
+ (MainWindow::addressUrl):
+ * QtTestBrowser/mainwindow.h:
+
+2011-01-27 Dirk Pranke <dpranke@chromium.org>
+
+ Reviewed by Mihai Parparita.
+
+ new-run-webkit-tests: turn off pixel tests correctly by default
+ for webkit-based ports. r70013 (bug 47510) used
+ port.set_option_default() to attempt to set default values, but
+ that didn't work correctly. I have removed set_option_default
+ for now since it was only being used in two places and in three
+ useless unit tests. There is a separate bug open to fix the
+ option parsing (48095), so this workaround is fine for now.
+
+ https://bugs.webkit.org/show_bug.cgi?id=53217
+
+ * Scripts/webkitpy/layout_tests/port/webkit.py:
+ * Scripts/webkitpy/layout_tests/port/base.py:
+ * Scripts/webkitpy/layout_tests/port/base_unittest.py:
+
+2011-01-27 Balazs Kelemen <kbalazs@webkit.org>
+
+ Rubber-stamped by Ariya Hidayat.
+
+ Trivial crash fix in WTR.
+
+ * WebKitTestRunner/TestController.cpp:
+ (WTR::TestController::initialize): Increase the size
+ of the vector by one to be able to store the null character.
+
+2011-01-27 Balazs Kelemen <kbalazs@webkit.org>
+
+ Reviewed by Csaba Osztrogonác.
+
+ [Qt][WK2] WTR should be initialized in the same way as DRT
+ https://bugs.webkit.org/show_bug.cgi?id=53240
+
+ * WebKitTestRunner/InjectedBundle/qt/ActivateFontsQt.cpp:
+ (WTR::activateFonts): Added missing initialization steps.
+
+2011-01-27 Joone Hur <joone.hur@collabora.co.uk>
+
+ Unreviewed.
+
+ Adding myself to committers.py.
+
+ * Scripts/webkitpy/common/config/committers.py:
+
+2011-01-27 Laszlo Gombos <laszlo.1.gombos@nokia.com>
+
+ Reviewed by Csaba Osztrogonác.
+
+ [Qt] [Symbian] Move project files into Source
+ https://bugs.webkit.org/show_bug.cgi?id=52891
+
+ Fix the Symbian build after the project files
+ are moved to Source directory. On Symbian qmake
+ needs to run in the same directory where the main
+ pro files (WebKit.pro, Tools.pro) are located.
+
+ * Scripts/webkitdirs.pm: Change to the directory where the pro file
+ is located before running qmake for Symbian. Qmake on Symbian
+ does not properly honor the "-o" option, work it around by setting
+ the name of the Makefile to bld.inf.
+
+2011-01-27 Zoltan Horvath <zoltan@webkit.org>
+
+ Reviewed by Andreas Kling.
+
+ [Qt] Add simple zooming features to MiniBrowser
+ https://bugs.webkit.org/show_bug.cgi?id=53231
+
+ Add View menu and Zoom In, Zoom Out, Zoom Reset actions to MiniBrowser.
+
+ * MiniBrowser/qt/BrowserWindow.cpp:
+ (BrowserWindow::BrowserWindow):
+ (BrowserWindow::zoomIn):
+ (BrowserWindow::zoomOut):
+ (BrowserWindow::resetZoom):
+ (BrowserWindow::updateUserAgentList):
+ (BrowserWindow::applyZoom):
+ * MiniBrowser/qt/BrowserWindow.h:
+
+2011-01-26 Maciej Stachowiak <mjs@apple.com>
+
+ Reviewed by Dan Bernstein.
+
+ WebKitTestRunner needs to support layoutTestController.evaluateInWebInspector
+ https://bugs.webkit.org/show_bug.cgi?id=42319
+
+ Add evaluateInWebInspector and other APIs needed for inspector tests to run.
+
+ * WebKitTestRunner/InjectedBundle/Bindings/LayoutTestController.idl:
+ * WebKitTestRunner/InjectedBundle/LayoutTestController.cpp:
+ (WTR::LayoutTestController::showWebInspector):
+ (WTR::LayoutTestController::closeWebInspector):
+ (WTR::LayoutTestController::evaluateInWebInspector):
+ (WTR::LayoutTestController::setTimelineProfilingEnabled):
+ * WebKitTestRunner/InjectedBundle/LayoutTestController.h:
+ * WebKitTestRunner/TestInvocation.cpp:
+ (WTR::shouldOpenWebInspector):
+ (WTR::TestInvocation::invoke):
+ * WebKitTestRunner/WebKitTestRunnerPrefix.h:
+
+2011-01-26 Martin Robinson <mrobinson@igalia.com>
+
+ Reviewed by Xan Lopez.
+
+ [GTK] Pixel dumps do not include scrollbars in output images
+ https://bugs.webkit.org/show_bug.cgi?id=53216
+
+ Show scrollbars in pixel dumps. This will fix pixel dumps for tests
+ that have scrollbars.
+
+ * DumpRenderTree/gtk/PixelDumpSupportGtk.cpp:
+ (createBitmapContextFromWebView): Take the snapshot of the containing GtkScrolledWindow
+ instead of the web view itself.
+
+2011-01-26 Dirk Pranke <dpranke@chromium.org>
+
+ Reviewed by Mihai Parparita.
+
+ Fix regression introduced in r76322 ... new-run-webkit-tests
+ was attempting to save the image diff output as a UTF-8-encoded
+ file.
+
+ https://bugs.webkit.org/show_bug.cgi?id=53210
+
+ * Scripts/webkitpy/layout_tests/port/webkit.py:
+
+2011-01-26 Sheriff Bot <webkit.review.bot@gmail.com>
+
+ Unreviewed, rolling out r76709.
+ http://trac.webkit.org/changeset/76709
+ https://bugs.webkit.org/show_bug.cgi?id=53194
+
+ "broke python tests on non-snowleopard platforms" (Requested
+ by dpranke on #webkit).
+
+ * Scripts/webkitpy/layout_tests/port/factory.py:
+ * Scripts/webkitpy/layout_tests/port/mock_drt.py: Removed.
+ * Scripts/webkitpy/layout_tests/port/mock_drt_unittest.py: Removed.
+
+2011-01-26 Dirk Pranke <dpranke@chromium.org>
+
+ Reviewed by Tony Chang.
+
+ new-run-webkit-tests: add a "mock DRT" port implementation
+ and a separate class that emulates what we expect the
+ DumpRenderTree behavior to be.
+
+ This will eventually replace port/dryrun.py and allow us to get
+ better test coverage of the new-run-webkit-tests code as well as
+ a reference for what new-run-webkit-tests expects from DRT.
+
+ This is the first attempt at this, and it is pretty bare-boned. It
+ really only has been tested on the 'mac' port (and a little on
+ the 'chromium-mac' port.
+
+ https://bugs.webkit.org/show_bug.cgi?id=53126
+
+ * Scripts/webkitpy/layout_tests/port/mock_drt.py: Added.
+ * Scripts/webkitpy/layout_tests/port/mock_drt_unittest.py: Added.
+ * Scripts/webkitpy/layout_tests/port/factory.py:
+
+2011-01-26 Xianzhu Wang <wangxianzhu@google.com>
+
+ Reviewed by Tony Chang.
+
+ Add '--no-timeout' option to Chromium DRT to ease debugging.
+ https://bugs.webkit.org/show_bug.cgi?id=52873
+
+ * DumpRenderTree/chromium/DumpRenderTree.cpp:
+ (main):
+
+2011-01-26 Csaba Osztrogonác <ossy@webkit.org>
+
+ Reviewed by Andreas Kling.
+
+ [Qt] Fix qt_minimal build
+ https://bugs.webkit.org/show_bug.cgi?id=53172
+
+ * QtTestBrowser/locationedit.h:
+
+2011-01-26 Mansi Mithal <mansi.mithal@nokia.com>
+
+ Reviewed by Antonio Gomes.
+
+ QtTestBrowser should have a UI Setting to disable plugins
+ https://bugs.webkit.org/show_bug.cgi?id=52408
+
+ Added a new action item named "Disable Plugins"
+ under the "Settings" menu.
+
+ * QtTestBrowser/launcherwindow.cpp:
+ (LauncherWindow::createChrome):
+ (LauncherWindow::togglePlugins):
+ * QtTestBrowser/launcherwindow.h:
+
+2011-01-25 Patrick Gansterer <paroga@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ Move main CMakeLists.txt into Source directory
+ https://bugs.webkit.org/show_bug.cgi?id=52888
+
+ * Scripts/webkitdirs.pm:
+
+2011-01-25 Patrick Gansterer <paroga@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ Improve label text in submit-to-ews
+ https://bugs.webkit.org/show_bug.cgi?id=53130
+
+ * QueueStatusServer/templates/submittoews.html:
+
+2011-01-25 Mansi Mithal <mansi.mithal@nokia.com>
+
+ Reviewed by Antonio Gomes.
+
+ QtTestBrowser should have a UI Settings to prevent loading images
+ https://bugs.webkit.org/show_bug.cgi?id=52409
+
+ Added a new action item named "DisableAutoLoadImages"
+ under the "Settings" menu
+
+ * QtTestBrowser/launcherwindow.cpp:
+ (LauncherWindow::createChrome):
+ (LauncherWindow::toggleAutoLoadImages):
+ * QtTestBrowser/launcherwindow.h:
+
+2011-01-25 Dirk Pranke <dpranke@chromium.org>
+
+ Reviewed by Tony Chang.
+
+ Minor bug fixes and cleanup for filesystem wrappers, port/* test
+ classes, test_expectations.py. This change adds "test-win" and
+ "test-mac" variants to the test port so that we can better test
+ rebaselining, and adds a MockUser() object for reuse in testing.
+
+ https://bugs.webkit.org/show_bug.cgi?id=53036
+
+ * Scripts/webkitpy/common/system/filesystem.py:
+ * Scripts/webkitpy/common/system/filesystem_mock.py:
+ * Scripts/webkitpy/layout_tests/layout_package/test_expectations.py:
+ * Scripts/webkitpy/layout_tests/port/factory.py:
+ * Scripts/webkitpy/layout_tests/port/base.py:
+ * Scripts/webkitpy/layout_tests/port/test.py:
+ * Scripts/webkitpy/layout_tests/run_webkit_tests_unittest.py:
+ * Scripts/webkitpy/layout_tests/rebaseline_chromium_webkit_tests_unittest.py:
+ * Scripts/webkitpy/tool/mocktool.py:
+
+2011-01-25 Tony Chang <tony@chromium.org>
+
+ Reviewed by Dimitri Glazkov.
+
+ [chromium] remove unused layoutTestController callback
+ https://bugs.webkit.org/show_bug.cgi?id=53103
+
+ This method is used by a test_shell_test, but not needed by DRT.
+
+ * DumpRenderTree/chromium/LayoutTestController.cpp:
+ (LayoutTestController::LayoutTestController):
+ * DumpRenderTree/chromium/LayoutTestController.h:
+
+2011-01-25 Gustavo Noronha Silva <gustavo.noronha@collabora.co.uk>
+
+ Reviewed by Andreas Kling.
+
+ [GTK] Remove 64 bits release bot from the buildbot master
+ https://bugs.webkit.org/show_bug.cgi?id=52899
+
+ Removes the 64 bits release slave from the buildbot configuration,
+ so that we can use it as an EWS.
+
+ * BuildSlaveSupport/build.webkit.org-config/config.json:
+
+2011-01-24 Maciej Stachowiak <mjs@apple.com>
+
+ Reviewed by Dan Bernstein.
+
+ Implement database quota callback to fix storage tests on WebKit2 bot
+ https://bugs.webkit.org/show_bug.cgi?id=53064
+
+ * WebKitTestRunner/TestController.cpp:
+ (WTR::exceededDatabaseQuota):
+ (WTR::TestController::createOtherPage):
+ (WTR::TestController::initialize):
+
+2011-01-24 Maciej Stachowiak <mjs@apple.com>
+
+ Reviewed by Anders Carlsson.
+
+ Use designated temp directory for the database for WebKit2
+ https://bugs.webkit.org/show_bug.cgi?id=53052
+
+ Adopt the new WK2 API for this.
+
+ * WebKitTestRunner/TestController.cpp:
+ (WTR::TestController::libraryPathForTesting):
+ (WTR::TestController::initialize):
+ * WebKitTestRunner/TestController.h:
+ * WebKitTestRunner/mac/TestControllerMac.mm:
+ (WTR::TestController::platformLibraryPathForTesting):
+ * WebKitTestRunner/qt/TestControllerQt.cpp:
+ (WTR::TestController::platformLibraryPathForTesting):
+ * WebKitTestRunner/win/TestControllerWin.cpp:
+ (WTR::TestController::platformLibraryPathForTesting):
+
+2011-01-24 Lucas Forschler <lforschler@apple.com>
+
+ Reviewed by Stephanie Lewis.
+
+ Add a new Leopard test bot.
+
+ * BuildSlaveSupport/build.webkit.org-config/config.json:
+
+2011-01-24 Gyuyoung Kim <gyuyoung.kim@samsung.com>
+
+ Reviewed by Adam Barth.
+
+ Add EFL Builder to core waterfall
+ https://bugs.webkit.org/show_bug.cgi?id=52704
+
+ Add EFL Builder to the core waterfall again.
+
+ * Scripts/webkitpy/common/net/buildbot/buildbot.py:
+ * Scripts/webkitpy/common/net/buildbot/buildbot_unittest.py:
+
+2011-01-24 Xianzhu Wang <wangxianzhu@google.com>
+
+ Reviewed by Tony Chang.
+
+ new-run-webkit-tests fails to start HTTP server if there are proxy settings
+ https://bugs.webkit.org/show_bug.cgi?id=52872
+
+ Force disabling proxy to resolve the problem.
+
+ * Scripts/webkitpy/layout_tests/port/http_server_base.py:
+ * Scripts/webkitpy/layout_tests/port/websocket_server.py:
+
+2011-01-24 Andreas Kling <kling@webkit.org>
+
+ Reviewed by Darin Adler.
+
+ check-webkit-style: Update exemptions following Source/ move.
+ https://bugs.webkit.org/show_bug.cgi?id=53017
+
+ * Scripts/webkitpy/style/checker.py:
+ * Scripts/webkitpy/style/checker_unittest.py:
+
+2011-01-24 Andras Becsi <abecsi@webkit.org>
+
+ Rubber-stamped by Csaba Osztrogonác.
+
+ [Qt] Move project files into Source
+ https://bugs.webkit.org/show_bug.cgi?id=52891
+
+ * DumpRenderTree/qt/ImageDiff.pro: Add missing "Source" to WebKit.pri path
+
+2011-01-24 Mikhail Naganov <mnaganov@chromium.org>
+
+ Reviewed by Yury Semikhatsky.
+
+ Web Inspector: Find duplicate strings in localizedStrings.js
+
+ https://bugs.webkit.org/show_bug.cgi?id=53005
+
+ * Scripts/check-inspector-strings:
+
+2011-01-24 Zoltan Horvath <zoltan@webkit.org>
+
+ Reviewed by Andreas Kling.
+
+ [Qt] Regroup MiniBrowser's menubar and add open file action
+ https://bugs.webkit.org/show_bug.cgi?id=53000
+
+ Add File and Develop menu to MiniBrowser's menubar and add open file action to File menu.
+
+ * MiniBrowser/qt/BrowserWindow.cpp:
+ (BrowserWindow::BrowserWindow):
+ (BrowserWindow::openFile):
+ (BrowserWindow::~BrowserWindow):
+ * MiniBrowser/qt/BrowserWindow.h:
+
+2011-01-24 Csaba Osztrogonác <ossy@webkit.org>
+
+ Unreviewed fix after r76496
+
+ [Qt] Move project files into Source
+ https://bugs.webkit.org/show_bug.cgi?id=52891
+
+ * BuildSlaveSupport/build.webkit.org-config/master.cfg: Remove unnecessary "Source" from the path.
+ * BuildSlaveSupport/built-product-archive: Remove unnecessary "Source" from the path.
+ * Scripts/webkitdirs.pm: Add the accidentally removed slash to the path.
+
+2011-01-24 Andras Becsi <abecsi@webkit.org>
+
+ Reviewed by Csaba Osztrogonác.
+
+ [Qt] Move project files into Source
+ https://bugs.webkit.org/show_bug.cgi?id=52891
+
+ * DerivedSources.pro: Renamed from DerivedSources.pro.
+ * DumpRenderTree/qt/DumpRenderTree.pro:
+ * DumpRenderTree/qt/TestNetscapePlugin/TestNetscapePlugin.pro:
+ * MiniBrowser/DerivedSources.pro:
+ * MiniBrowser/qt/MiniBrowser.pro:
+ * QtTestBrowser/QtTestBrowser.pro:
+ * Scripts/webkitdirs.pm:
+ * Tools.pro: Added.
+ * WebKitTestRunner/DerivedSources.pro:
+ * WebKitTestRunner/InjectedBundle/qt/InjectedBundle.pro:
+ * WebKitTestRunner/qt/WebKitTestRunner.pro:
+
+2011-01-22 Geoffrey Garen <ggaren@apple.com>
+
+ Reviewed by Dan Bernstein.
+
+ Beefed up --threaded mode to catch even more kinds of errors.
+ https://bugs.webkit.org/show_bug.cgi?id=52971
+
+ * DumpRenderTree/pthreads/JavaScriptThreadingPthreads.cpp: Use a shared
+ context group to force JSC to mark multiple threads. (This used to be
+ the default, but it changed in SnowLeopard.)
+ (runJavaScriptThread): Do more locking and unlocking, and more allocation,
+ to give threading mistakes more chances to show themselves.
+ (startJavaScriptThreads):
+ (stopJavaScriptThreads):
+
+2011-01-22 Robert Hogan <robert@webkit.org>
+
+ Reviewed by Andreas Kling.
+
+ [Qt] Support layoutTestController.addURLToRedirect()
+ https://bugs.webkit.org/show_bug.cgi?id=52956
+
+ * DumpRenderTree/qt/LayoutTestControllerQt.cpp:
+ (LayoutTestController::addURLToRedirect):
+ * DumpRenderTree/qt/LayoutTestControllerQt.h:
+
+2011-01-22 Robert Hogan <robert@webkit.org>
+
+ Reviewed by Kenneth Rohde Christiansen.
+
+ [Qt] REGRESSION (r72360): http/tests/security/aboutBlank/xss-DENIED-* tests fail
+ https://bugs.webkit.org/show_bug.cgi?id=49802
+
+ * DumpRenderTree/qt/DumpRenderTreeQt.cpp:
+ (WebCore::DumpRenderTree::resetToConsistentStateBeforeTesting):
+ (WebCore::DumpRenderTree::open):
+
+2011-01-21 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Maciej Stachowiak.
+
+ Disable mac_unittest.py that fails on some of the Mac bots
+ https://bugs.webkit.org/show_bug.cgi?id=52947
+
+ As noted in the comment, this test does not appear to be correct
+ because the function this test is testing returns different results
+ depending on which flavor of Mac the test is run on. This patch
+ disable the test. Hopefully we can re-enable the test once we've
+ probably insulated the test from its environment.
+
+ * Scripts/webkitpy/layout_tests/port/mac_unittest.py:
+
+2011-01-21 Dirk Pranke <dpranke@chromium.org>
+
+ Reviewed by Mihai Parparita.
+
+ Fix bug introduced in r76322 that caused NRWT to not actually
+ read the Skipped files properly.
+
+ https://bugs.webkit.org/show_bug.cgi?id=52771
+
+ * Scripts/webkitpy/layout_tests/port/mac_unittest.py:
+ * Scripts/webkitpy/layout_tests/port/webkit.py:
+ * Scripts/webkitpy/layout_tests/port/webkit_unittest.py:
+
2011-01-21 Sam Weinig <sam@webkit.org>
Reviewed by Geoffrey Sean Garen and Mark Rowe.
diff --git a/Tools/DerivedSources.pro b/Tools/DerivedSources.pro
new file mode 100644
index 0000000..55a26a2
--- /dev/null
+++ b/Tools/DerivedSources.pro
@@ -0,0 +1,16 @@
+TEMPLATE = subdirs
+CONFIG += ordered
+
+SUBDIRS += \
+ MiniBrowser/DerivedSources.pro \
+ WebKitTestRunner/DerivedSources.pro
+
+for(subpro, SUBDIRS) {
+ subdir = $${dirname(subpro)}
+ subtarget = $$replace(subpro, [^a-zA-Z0-9_], -)
+ eval($${subtarget}.makefile = "Makefile.DerivedSources")
+ eval(generated_files-$${subtarget}.commands = (cd $$subdir && $(MAKE) -f Makefile.DerivedSources generated_files))
+ QMAKE_EXTRA_TARGETS += generated_files-$${subtarget}
+ generated_files.depends += generated_files-$${subtarget}
+}
+QMAKE_EXTRA_TARGETS += generated_files
diff --git a/Tools/DumpRenderTree/AccessibilityController.cpp b/Tools/DumpRenderTree/AccessibilityController.cpp
index 798389f..4fcd4f5 100644
--- a/Tools/DumpRenderTree/AccessibilityController.cpp
+++ b/Tools/DumpRenderTree/AccessibilityController.cpp
@@ -77,6 +77,13 @@ static JSValueRef logScrollingStartEventsCallback(JSContextRef ctx, JSObjectRef,
return JSValueMakeUndefined(ctx);
}
+static JSValueRef logAccessibilityEventsCallback(JSContextRef ctx, JSObjectRef, JSObjectRef thisObject, size_t, const JSValueRef[], JSValueRef*)
+{
+ AccessibilityController* controller = static_cast<AccessibilityController*>(JSObjectGetPrivate(thisObject));
+ controller->setLogAccessibilityEvents(true);
+ return JSValueMakeUndefined(ctx);
+}
+
static JSValueRef getElementAtPointCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
{
int x = 0;
@@ -96,6 +103,7 @@ JSClassRef AccessibilityController::getJSClass()
{ "logFocusEvents", logFocusEventsCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
{ "logValueChangeEvents", logValueChangeEventsCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
{ "logScrollingStartEvents", logScrollingStartEventsCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "logAccessibilityEvents", logAccessibilityEventsCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
{ "elementAtPoint", getElementAtPointCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
{ 0, 0, 0 }
};
@@ -119,4 +127,5 @@ void AccessibilityController::resetToConsistentState()
setLogFocusEvents(false);
setLogValueChangeEvents(false);
setLogScrollingStartEvents(false);
+ setLogAccessibilityEvents(false);
}
diff --git a/Tools/DumpRenderTree/AccessibilityController.h b/Tools/DumpRenderTree/AccessibilityController.h
index 5a6ca13..462c484 100644
--- a/Tools/DumpRenderTree/AccessibilityController.h
+++ b/Tools/DumpRenderTree/AccessibilityController.h
@@ -50,6 +50,7 @@ public:
void setLogFocusEvents(bool);
void setLogValueChangeEvents(bool);
void setLogScrollingStartEvents(bool);
+ void setLogAccessibilityEvents(bool);
void resetToConsistentState();
diff --git a/Tools/DumpRenderTree/DumpRenderTree.gypi b/Tools/DumpRenderTree/DumpRenderTree.gypi
index b7de580..3c3384d 100644
--- a/Tools/DumpRenderTree/DumpRenderTree.gypi
+++ b/Tools/DumpRenderTree/DumpRenderTree.gypi
@@ -53,8 +53,12 @@
'TestNetscapePlugIn/TestObject.cpp',
'TestNetscapePlugIn/TestObject.h',
'TestNetscapePlugIn/Tests/DocumentOpenInDestroyStream.cpp',
+ 'TestNetscapePlugIn/Tests/EvaluateJSAfterRemovingPluginElement.cpp',
+ 'TestNetscapePlugIn/Tests/GetUserAgentWithNullNPPFromNPPNew.cpp',
'TestNetscapePlugIn/Tests/NPRuntimeObjectFromDestroyedPlugin.cpp',
'TestNetscapePlugIn/Tests/NPRuntimeRemoveProperty.cpp',
+ 'TestNetscapePlugIn/Tests/NullNPPGetValuePointer.cpp',
+ 'TestNetscapePlugIn/Tests/PassDifferentNPPStruct.cpp',
'TestNetscapePlugIn/Tests/PluginScriptableNPObjectInvokeDefault.cpp',
'TestNetscapePlugIn/main.cpp',
],
diff --git a/Tools/DumpRenderTree/LayoutTestController.cpp b/Tools/DumpRenderTree/LayoutTestController.cpp
index 1133a88..29eeeb0 100644
--- a/Tools/DumpRenderTree/LayoutTestController.cpp
+++ b/Tools/DumpRenderTree/LayoutTestController.cpp
@@ -445,6 +445,17 @@ static JSValueRef displayCallback(JSContextRef context, JSObjectRef function, JS
return JSValueMakeUndefined(context);
}
+static JSValueRef displayInvalidatedRegionCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ // Has mac & windows implementation
+ LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject));
+ // LayoutTestController::display() only renders the invalidated region so
+ // we can just use that.
+ controller->display();
+
+ return JSValueMakeUndefined(context);
+}
+
static JSValueRef encodeHostNameCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
{
// Has mac implementation
@@ -1980,6 +1991,7 @@ JSStaticFunction* LayoutTestController::staticFunctions()
{ "disableImageLoading", disableImageLoadingCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
{ "dispatchPendingLoadRequests", dispatchPendingLoadRequestsCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
{ "display", displayCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "displayInvalidatedRegion", displayInvalidatedRegionCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
{ "dumpApplicationCacheDelegateCallbacks", dumpApplicationCacheDelegateCallbacksCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
{ "dumpAsText", dumpAsTextCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
{ "dumpBackForwardList", dumpBackForwardListCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
diff --git a/Tools/DumpRenderTree/LayoutTestController.h b/Tools/DumpRenderTree/LayoutTestController.h
index b80d805..11558dd 100644
--- a/Tools/DumpRenderTree/LayoutTestController.h
+++ b/Tools/DumpRenderTree/LayoutTestController.h
@@ -59,6 +59,7 @@ public:
void disableImageLoading();
void dispatchPendingLoadRequests();
void display();
+ void displayInvalidatedRegion();
void execCommand(JSStringRef name, JSStringRef value);
bool findString(JSContextRef, JSStringRef, JSObjectRef optionsArray);
bool isCommandEnabled(JSStringRef name);
diff --git a/Tools/DumpRenderTree/TestNetscapePlugIn/PluginObject.cpp b/Tools/DumpRenderTree/TestNetscapePlugIn/PluginObject.cpp
index 45e5ddb..24ee12c 100644
--- a/Tools/DumpRenderTree/TestNetscapePlugIn/PluginObject.cpp
+++ b/Tools/DumpRenderTree/TestNetscapePlugIn/PluginObject.cpp
@@ -199,6 +199,7 @@ enum {
ID_SET_STATUS,
ID_RESIZE_TO,
ID_NORMALIZE,
+ ID_INVALIDATE_RECT,
NUM_METHOD_IDENTIFIERS
};
@@ -239,7 +240,8 @@ static const NPUTF8 *pluginMethodIdentifierNames[NUM_METHOD_IDENTIFIERS] = {
"refCount",
"setStatus",
"resizeTo",
- "normalize"
+ "normalize",
+ "invalidateRect"
};
static NPUTF8* createCStringFromNPVariant(const NPVariant* variant)
@@ -986,6 +988,20 @@ static bool normalizeOverride(PluginObject* obj, const NPVariant* args, uint32_t
return true;
}
+static bool invalidateRect(PluginObject* obj, const NPVariant* args, uint32_t argCount, NPVariant* result)
+{
+ if (argCount != 4)
+ return false;
+
+ NPRect rect;
+ rect.left = static_cast<int>(NPVARIANT_TO_DOUBLE(args[0]));
+ rect.top = static_cast<int>(NPVARIANT_TO_DOUBLE(args[1]));
+ rect.right = static_cast<int>(NPVARIANT_TO_DOUBLE(args[2]));
+ rect.bottom = static_cast<int>(NPVARIANT_TO_DOUBLE(args[3]));
+
+ browser->invalidaterect(obj->npp, &rect);
+ return true;
+}
static bool pluginInvoke(NPObject* header, NPIdentifier name, const NPVariant* args, uint32_t argCount, NPVariant* result)
{
@@ -1101,6 +1117,8 @@ static bool pluginInvoke(NPObject* header, NPIdentifier name, const NPVariant* a
return testResizeTo(plugin, args, argCount, result);
if (name == pluginMethodIdentifiers[ID_NORMALIZE])
return normalizeOverride(plugin, args, argCount, result);
+ if (name == pluginMethodIdentifiers[ID_INVALIDATE_RECT])
+ return invalidateRect(plugin, args, argCount, result);
return false;
}
diff --git a/Tools/DumpRenderTree/TestNetscapePlugIn/PluginTest.cpp b/Tools/DumpRenderTree/TestNetscapePlugIn/PluginTest.cpp
index 703d9d5..0dd9da6 100644
--- a/Tools/DumpRenderTree/TestNetscapePlugIn/PluginTest.cpp
+++ b/Tools/DumpRenderTree/TestNetscapePlugIn/PluginTest.cpp
@@ -33,11 +33,14 @@ extern NPNetscapeFuncs *browser;
PluginTest* PluginTest::create(NPP npp, const string& identifier)
{
+ if (identifier.empty())
+ return new PluginTest(npp, identifier);
+
CreateTestFunction createTestFunction = createTestFunctions()[identifier];
if (createTestFunction)
return createTestFunction(npp, identifier);
- return new PluginTest(npp, identifier);
+ return 0;
}
PluginTest::PluginTest(NPP npp, const string& identifier)
diff --git a/Tools/DumpRenderTree/TestNetscapePlugIn/main.cpp b/Tools/DumpRenderTree/TestNetscapePlugIn/main.cpp
index b4b7fa3..7635a09 100644
--- a/Tools/DumpRenderTree/TestNetscapePlugIn/main.cpp
+++ b/Tools/DumpRenderTree/TestNetscapePlugIn/main.cpp
@@ -200,6 +200,9 @@ NPError NPP_New(NPMIMEType pluginType, NPP instance, uint16_t mode, int16_t argc
else if (strcasecmp(argn[i], "src") == 0 &&
strcasecmp(argv[i], "data:application/x-webkit-test-netscape,returnerrorfromnewstream") == 0)
obj->returnErrorFromNewStream = TRUE;
+ else if (strcasecmp(argn[i], "src") == 0 &&
+ strcasecmp(argv[i], "data:application/x-webkit-test-netscape,alertwhenloaded") == 0)
+ executeScript(obj, "alert('Plugin Loaded!')");
else if (strcasecmp(argn[i], "onSetWindow") == 0 && !obj->onSetWindow)
obj->onSetWindow = strdup(argv[i]);
else if (strcasecmp(argn[i], "onNew") == 0 && !onNewScript)
@@ -256,6 +259,15 @@ NPError NPP_New(NPMIMEType pluginType, NPP instance, uint16_t mode, int16_t argc
// When testing evaluate script on mouse-down or key-down, allow event logging to handle events.
if (obj->evaluateScriptOnMouseDownOrKeyDown)
obj->eventLogging = true;
+ } else if (!strcasecmp(argn[i], "windowedPlugin")) {
+ void* windowed = 0;
+ if (!strcasecmp(argv[i], "false") || !strcasecmp(argv[i], "0"))
+ windowed = 0;
+ else if (!strcasecmp(argv[i], "true") || !strcasecmp(argv[i], "1"))
+ windowed = reinterpret_cast<void*>(1);
+ else
+ assert(false);
+ browser->setvalue(instance, NPPVpluginWindowBool, windowed);
}
}
@@ -271,6 +283,11 @@ NPError NPP_New(NPMIMEType pluginType, NPP instance, uint16_t mode, int16_t argc
obj->pluginTest = PluginTest::create(instance, testIdentifier);
+ if (!obj->pluginTest) {
+ pluginLog(instance, "NPP_New: Could not find a test named \"%s\", maybe its .cpp file wasn't added to the build system?", testIdentifier.c_str());
+ return NPERR_GENERIC_ERROR;
+ }
+
#ifdef XP_UNIX
// On Unix, plugins only get events if they are windowless.
browser->setvalue(instance, NPPVpluginWindowBool, 0);
@@ -663,6 +680,19 @@ static int16_t handleEventX11(NPP instance, PluginObject* obj, XEvent* event)
}
#endif // XP_UNIX
+#ifdef XP_WIN
+static int16_t handleEventWin(NPP instance, PluginObject* obj, NPEvent* event)
+{
+ switch (event->event) {
+ case WM_PAINT:
+ if (obj->onPaintEvent)
+ executeScript(obj, obj->onPaintEvent);
+ return 1;
+ }
+ return 0;
+}
+#endif // XP_WIN
+
int16_t NPP_HandleEvent(NPP instance, void *event)
{
PluginObject* obj = static_cast<PluginObject*>(instance->pdata);
@@ -677,6 +707,8 @@ int16_t NPP_HandleEvent(NPP instance, void *event)
return handleEventCocoa(instance, obj, static_cast<NPCocoaEvent*>(event));
#elif defined(XP_UNIX)
return handleEventX11(instance, obj, static_cast<XEvent*>(event));
+#elif defined(XP_WIN)
+ return handleEventWin(instance, obj, static_cast<NPEvent*>(event));
#else
// FIXME: Implement for other platforms.
return 0;
diff --git a/Tools/DumpRenderTree/chromium/DumpRenderTree.cpp b/Tools/DumpRenderTree/chromium/DumpRenderTree.cpp
index bd5075c..7e9010f 100644
--- a/Tools/DumpRenderTree/chromium/DumpRenderTree.cpp
+++ b/Tools/DumpRenderTree/chromium/DumpRenderTree.cpp
@@ -58,6 +58,7 @@ static const char optionEnableAccelerated2DCanvas[] = "--enable-accelerated-2d-c
static const char optionStressOpt[] = "--stress-opt";
static const char optionStressDeopt[] = "--stress-deopt";
static const char optionJavaScriptFlags[] = "--js-flags=";
+static const char optionNoTimeout[] = "--no-timeout=";
static void runTest(TestShell& shell, TestParams& params, const string& testName, bool testShellMode)
{
@@ -123,6 +124,7 @@ int main(int argc, char* argv[])
bool stressDeopt = false;
bool hardwareAcceleratedGL = false;
string javaScriptFlags;
+ bool noTimeout = false;
for (int i = 1; i < argc; ++i) {
string argument(argv[i]);
if (argument == "-")
@@ -155,6 +157,8 @@ int main(int argc, char* argv[])
stressDeopt = true;
else if (!argument.find(optionJavaScriptFlags))
javaScriptFlags = argument.substr(strlen(optionJavaScriptFlags));
+ else if (!argument.find(optionNoTimeout))
+ noTimeout = true;
else if (argument.size() && argument[0] == '-')
fprintf(stderr, "Unknown option: %s\n", argv[i]);
else
@@ -182,6 +186,10 @@ int main(int argc, char* argv[])
shell.setJavaScriptFlags(javaScriptFlags);
shell.setStressOpt(stressOpt);
shell.setStressDeopt(stressDeopt);
+ if (noTimeout) {
+ // 0x20000000ms is big enough for the purpose to avoid timeout in debugging.
+ shell.setLayoutTestTimeout(0x20000000);
+ }
if (serverMode && !tests.size()) {
params.printSeparators = true;
char testString[2048]; // 2048 is the same as the sizes of other platforms.
diff --git a/Tools/DumpRenderTree/chromium/ImageDiff.cpp b/Tools/DumpRenderTree/chromium/ImageDiff.cpp
index f2875dd..d676430 100644
--- a/Tools/DumpRenderTree/chromium/ImageDiff.cpp
+++ b/Tools/DumpRenderTree/chromium/ImageDiff.cpp
@@ -88,7 +88,7 @@ public:
if (!byteLength)
return false;
- OwnArrayPtr<unsigned char> source(new unsigned char[byteLength]);
+ OwnArrayPtr<unsigned char> source = adoptArrayPtr(new unsigned char[byteLength]);
if (fread(source.get(), 1, byteLength, stdin) != byteLength)
return false;
diff --git a/Tools/DumpRenderTree/chromium/LayoutTestController.cpp b/Tools/DumpRenderTree/chromium/LayoutTestController.cpp
index 529019b..59537c6 100644
--- a/Tools/DumpRenderTree/chromium/LayoutTestController.cpp
+++ b/Tools/DumpRenderTree/chromium/LayoutTestController.cpp
@@ -89,6 +89,7 @@ LayoutTestController::LayoutTestController(TestShell* shell)
bindMethod("counterValueForElementById", &LayoutTestController::counterValueForElementById);
bindMethod("disableImageLoading", &LayoutTestController::disableImageLoading);
bindMethod("display", &LayoutTestController::display);
+ bindMethod("displayInvalidatedRegion", &LayoutTestController::displayInvalidatedRegion);
bindMethod("dumpAsText", &LayoutTestController::dumpAsText);
bindMethod("dumpBackForwardList", &LayoutTestController::dumpBackForwardList);
bindMethod("dumpChildFramesAsText", &LayoutTestController::dumpChildFramesAsText);
@@ -106,7 +107,6 @@ LayoutTestController::LayoutTestController(TestShell* shell)
bindMethod("evaluateInWebInspector", &LayoutTestController::evaluateInWebInspector);
bindMethod("evaluateScriptInIsolatedWorld", &LayoutTestController::evaluateScriptInIsolatedWorld);
bindMethod("execCommand", &LayoutTestController::execCommand);
- bindMethod("forceRedSelectionColors", &LayoutTestController::forceRedSelectionColors);
bindMethod("grantDesktopNotificationPermission", &LayoutTestController::grantDesktopNotificationPermission);
bindMethod("isCommandEnabled", &LayoutTestController::isCommandEnabled);
bindMethod("layerTreeAsText", &LayoutTestController::layerTreeAsText);
@@ -628,9 +628,11 @@ void LayoutTestController::setAlwaysAcceptCookies(const CppArgumentList& argumen
result->setNull();
}
-void LayoutTestController::setAsynchronousSpellCheckingEnabled(const CppArgumentList&, CppVariant*)
+void LayoutTestController::setAsynchronousSpellCheckingEnabled(const CppArgumentList& arguments, CppVariant* result)
{
- // FIXME: Implement this.
+ if (arguments.size() > 0 && arguments[0].isBool())
+ m_shell->webView()->settings()->setAsynchronousSpellCheckingEnabled(cppVariantToBool(arguments[0]));
+ result->setNull();
}
void LayoutTestController::showWebInspector(const CppArgumentList&, CppVariant* result)
@@ -800,11 +802,11 @@ void LayoutTestController::pathToLocalResource(const CppArgumentList& arguments,
// We want a temp file.
const unsigned tempPrefixLength = 5;
size_t bufferSize = MAX_PATH;
- OwnArrayPtr<WCHAR> tempPath(new WCHAR[bufferSize]);
+ OwnArrayPtr<WCHAR> tempPath = adoptArrayPtr(new WCHAR[bufferSize]);
DWORD tempLength = ::GetTempPathW(bufferSize, tempPath.get());
if (tempLength + url.length() - tempPrefixLength + 1 > bufferSize) {
bufferSize = tempLength + url.length() - tempPrefixLength + 1;
- tempPath.set(new WCHAR[bufferSize]);
+ tempPath = adoptArrayPtr(new WCHAR[bufferSize]);
tempLength = GetTempPathW(bufferSize, tempPath.get());
ASSERT(tempLength < bufferSize);
}
@@ -1083,6 +1085,14 @@ void LayoutTestController::display(const CppArgumentList& arguments, CppVariant*
result->setNull();
}
+void LayoutTestController::displayInvalidatedRegion(const CppArgumentList& arguments, CppVariant* result)
+{
+ WebViewHost* host = m_shell->webViewHost();
+ host->paintInvalidatedRegion();
+ host->displayRepaintMask();
+ result->setNull();
+}
+
void LayoutTestController::testRepaint(const CppArgumentList&, CppVariant* result)
{
m_testRepaint = true;
@@ -1464,12 +1474,6 @@ void LayoutTestController::evaluateInWebInspector(const CppArgumentList& argumen
m_shell->drtDevToolsAgent()->evaluateInWebInspector(arguments[0].toInt32(), arguments[1].toString());
}
-void LayoutTestController::forceRedSelectionColors(const CppArgumentList& arguments, CppVariant* result)
-{
- result->setNull();
- m_shell->webView()->setSelectionColors(0xffee0000, 0xff00ee00, 0xff000000, 0xffc0c0c0);
-}
-
void LayoutTestController::addUserScript(const CppArgumentList& arguments, CppVariant* result)
{
result->setNull();
diff --git a/Tools/DumpRenderTree/chromium/LayoutTestController.h b/Tools/DumpRenderTree/chromium/LayoutTestController.h
index 13d1447..0ef8607 100644
--- a/Tools/DumpRenderTree/chromium/LayoutTestController.h
+++ b/Tools/DumpRenderTree/chromium/LayoutTestController.h
@@ -250,6 +250,7 @@ public:
void dumpTitleChanges(const CppArgumentList&, CppVariant*);
void setMainFrameIsFirstResponder(const CppArgumentList&, CppVariant*);
void display(const CppArgumentList&, CppVariant*);
+ void displayInvalidatedRegion(const CppArgumentList&, CppVariant*);
void testRepaint(const CppArgumentList&, CppVariant*);
void repaintSweepHorizontally(const CppArgumentList&, CppVariant*);
void clearBackForwardList(const CppArgumentList&, CppVariant*);
@@ -311,9 +312,6 @@ public:
// Allows layout tests to exec scripts at WebInspector side.
void evaluateInWebInspector(const CppArgumentList&, CppVariant*);
- // Forces the selection colors for testing under Linux.
- void forceRedSelectionColors(const CppArgumentList&, CppVariant*);
-
// Adds a user script or user style sheet to be injected into new documents.
void addUserScript(const CppArgumentList&, CppVariant*);
void addUserStyleSheet(const CppArgumentList&, CppVariant*);
diff --git a/Tools/DumpRenderTree/chromium/NotificationPresenter.cpp b/Tools/DumpRenderTree/chromium/NotificationPresenter.cpp
index 7e7053b..63a70e4 100644
--- a/Tools/DumpRenderTree/chromium/NotificationPresenter.cpp
+++ b/Tools/DumpRenderTree/chromium/NotificationPresenter.cpp
@@ -95,7 +95,7 @@ bool NotificationPresenter::show(const WebNotification& notification)
notification.url().spec().data());
} else {
printf("DESKTOP NOTIFICATION:%s icon %s, title %s, text %s\n",
- notification.dir() == "rtl" ? "(RTL)" : "",
+ notification.direction() == WebTextDirectionRightToLeft ? "(RTL)" : "",
notification.iconURL().isEmpty() ? "" :
notification.iconURL().spec().data(),
notification.title().isEmpty() ? "" :
diff --git a/Tools/DumpRenderTree/chromium/TestShell.cpp b/Tools/DumpRenderTree/chromium/TestShell.cpp
index ec6a502..11a598f 100644
--- a/Tools/DumpRenderTree/chromium/TestShell.cpp
+++ b/Tools/DumpRenderTree/chromium/TestShell.cpp
@@ -93,6 +93,7 @@ TestShell::TestShell(bool testShellMode)
WebRuntimeFeatures::enableGeolocation(true);
WebRuntimeFeatures::enableIndexedDatabase(true);
WebRuntimeFeatures::enableFileSystem(true);
+ WebRuntimeFeatures::enableJavaScriptI18NAPI(true);
m_accessibilityController.set(new AccessibilityController(this));
m_layoutTestController.set(new LayoutTestController(this));
m_eventSender.set(new EventSender(this));
diff --git a/Tools/DumpRenderTree/chromium/WebViewHost.cpp b/Tools/DumpRenderTree/chromium/WebViewHost.cpp
index 18b107f..e1a2fcb 100644
--- a/Tools/DumpRenderTree/chromium/WebViewHost.cpp
+++ b/Tools/DumpRenderTree/chromium/WebViewHost.cpp
@@ -52,6 +52,8 @@
#include "WebSize.h"
#include "WebSpeechInputControllerMock.h"
#include "WebStorageNamespace.h"
+#include "WebTextCheckingCompletion.h"
+#include "WebTextCheckingResult.h"
#include "WebURLRequest.h"
#include "WebURLResponse.h"
#include "WebView.h"
@@ -60,6 +62,7 @@
#include "webkit/support/webkit_support.h"
#include <wtf/Assertions.h>
#include <wtf/PassOwnPtr.h>
+#include <wtf/Vector.h>
using namespace WebCore;
using namespace WebKit;
@@ -225,6 +228,12 @@ static string textAffinityDescription(WebTextAffinity affinity)
return "(UNKNOWN AFFINITY)";
}
+static void invokeFinishLastTextCheck(void* context)
+{
+ WebViewHost* wvh = static_cast<WebViewHost*>(context);
+ wvh->finishLastTextCheck();
+}
+
// WebViewClient -------------------------------------------------------------
WebView* WebViewHost::createView(WebFrame*, const WebURLRequest&, const WebWindowFeatures&, const WebString&)
@@ -409,6 +418,35 @@ void WebViewHost::spellCheck(const WebString& text, int& misspelledOffset, int&
m_spellcheck.spellCheckWord(text, &misspelledOffset, &misspelledLength);
}
+void WebViewHost::requestCheckingOfText(const WebString& text, WebTextCheckingCompletion* completion)
+{
+ m_lastRequestedTextCheckingCompletion = completion;
+ m_lastRequestedTextCheckString = text;
+ webkit_support::PostDelayedTask(invokeFinishLastTextCheck, static_cast<void*>(this), 0);
+}
+
+void WebViewHost::finishLastTextCheck()
+{
+ Vector<WebTextCheckingResult> results;
+ // FIXME: Do the grammar check.
+ int offset = 0;
+ String text(m_lastRequestedTextCheckString.data(), m_lastRequestedTextCheckString.length());
+ while (text.length()) {
+ int misspelledPosition = 0;
+ int misspelledLength = 0;
+ m_spellcheck.spellCheckWord(WebString(text.characters(), text.length()), &misspelledPosition, &misspelledLength);
+ if (!misspelledLength)
+ break;
+ results.append(WebTextCheckingResult(WebTextCheckingResult::ErrorSpelling, offset + misspelledPosition, misspelledLength));
+ text = text.substring(misspelledPosition + misspelledLength);
+ offset += misspelledPosition;
+ }
+
+ m_lastRequestedTextCheckingCompletion->didFinishCheckingText(results);
+ m_lastRequestedTextCheckingCompletion = 0;
+}
+
+
WebString WebViewHost::autoCorrectWord(const WebString&)
{
// Returns an empty string as Mac WebKit ('WebKitSupport/WebEditorClient.mm')
@@ -1094,7 +1132,7 @@ void WebViewHost::didDisplayInsecureContent(WebFrame*)
fputs("didDisplayInsecureContent\n", stdout);
}
-void WebViewHost::didRunInsecureContent(WebFrame*, const WebSecurityOrigin& origin)
+void WebViewHost::didRunInsecureContent(WebFrame*, const WebSecurityOrigin& origin, const WebURL& insecureURL)
{
if (m_shell->shouldDumpFrameLoadCallbacks())
fputs("didRunInsecureContent\n", stdout);
@@ -1115,6 +1153,7 @@ void WebViewHost::openFileSystem(WebFrame* frame, WebFileSystem::Type type, long
WebViewHost::WebViewHost(TestShell* shell)
: m_shell(shell)
, m_webWidget(0)
+ , m_lastRequestedTextCheckingCompletion(0)
{
reset();
}
diff --git a/Tools/DumpRenderTree/chromium/WebViewHost.h b/Tools/DumpRenderTree/chromium/WebViewHost.h
index 83d21dc..e6d82ae 100644
--- a/Tools/DumpRenderTree/chromium/WebViewHost.h
+++ b/Tools/DumpRenderTree/chromium/WebViewHost.h
@@ -126,6 +126,7 @@ class WebViewHost : public WebKit::WebViewClient, public WebKit::WebFrameClient,
virtual void didEndEditing();
virtual bool handleCurrentKeyboardEvent();
virtual void spellCheck(const WebKit::WebString&, int& offset, int& length);
+ virtual void requestCheckingOfText(const WebKit::WebString&, WebKit::WebTextCheckingCompletion*);
virtual WebKit::WebString autoCorrectWord(const WebKit::WebString&);
virtual void runModalAlertDialog(WebKit::WebFrame*, const WebKit::WebString&);
virtual bool runModalConfirmDialog(WebKit::WebFrame*, const WebKit::WebString&);
@@ -202,12 +203,15 @@ class WebViewHost : public WebKit::WebViewClient, public WebKit::WebFrameClient,
virtual void didFinishResourceLoad(WebKit::WebFrame*, unsigned identifier);
virtual void didFailResourceLoad(WebKit::WebFrame*, unsigned identifier, const WebKit::WebURLError&);
virtual void didDisplayInsecureContent(WebKit::WebFrame*);
- virtual void didRunInsecureContent(WebKit::WebFrame*, const WebKit::WebSecurityOrigin&);
+ virtual void didRunInsecureContent(WebKit::WebFrame*, const WebKit::WebSecurityOrigin&, const WebKit::WebURL&);
virtual bool allowScript(WebKit::WebFrame*, bool enabledPerSettings);
virtual void openFileSystem(WebKit::WebFrame*, WebKit::WebFileSystem::Type, long long size, bool create, WebKit::WebFileSystemCallbacks*);
WebKit::WebDeviceOrientationClientMock* deviceOrientationClientMock();
+
+ // Spellcheck related helper APIs
MockSpellCheck* mockSpellCheck();
+ void finishLastTextCheck();
// Geolocation client mocks for LayoutTestController
WebKit::WebGeolocationClientMock* geolocationClientMock();
@@ -320,6 +324,9 @@ private:
OwnPtr<WebKit::WebSpeechInputControllerMock> m_speechInputControllerMock;
OwnPtr<TestNavigationController*> m_navigationController;
+
+ WebKit::WebString m_lastRequestedTextCheckString;
+ WebKit::WebTextCheckingCompletion* m_lastRequestedTextCheckingCompletion;
};
#endif // WebViewHost_h
diff --git a/Tools/DumpRenderTree/gtk/AccessibilityCallbacks.cpp b/Tools/DumpRenderTree/gtk/AccessibilityCallbacks.cpp
new file mode 100644
index 0000000..be66513
--- /dev/null
+++ b/Tools/DumpRenderTree/gtk/AccessibilityCallbacks.cpp
@@ -0,0 +1,196 @@
+/*
+ * Copyright (C) 2011 Igalia S.L.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "AccessibilityCallbacks.h"
+
+#include "AccessibilityController.h"
+#include "DumpRenderTree.h"
+#include "GOwnPtr.h"
+#include "WebCoreSupport/DumpRenderTreeSupportGtk.h"
+#include <gtk/gtk.h>
+#include <webkit/webkit.h>
+
+static guint stateChangeListenerId = 0;
+static guint focusEventListenerId = 0;
+static guint activeDescendantChangedListenerId = 0;
+static guint childrenChangedListenerId = 0;
+static guint propertyChangedListenerId = 0;
+static guint visibleDataChangedListenerId = 0;
+
+static guint loadCompleteListenerId = 0;
+static guint loadStoppedListenerId = 0;
+static guint reloadListenerId = 0;
+
+static void printAccessibilityEvent(AtkObject* accessible, const gchar* signalName)
+{
+ // Sanity check.
+ if (!accessible || !ATK_IS_OBJECT(accessible) || !signalName)
+ return;
+
+ const gchar* objectName = atk_object_get_name(accessible);
+ guint objectRole = atk_object_get_role(accessible);
+
+ // Try to always provide a name to be logged for the object.
+ if (!objectName || *objectName == '\0')
+ objectName = "(No name)";
+
+ printf("Accessibility object emitted \"%s\" / Name: \"%s\" / Role: %d\n",
+ signalName, objectName, objectRole);
+}
+
+static gboolean axObjectEventListener(GSignalInvocationHint *signalHint,
+ guint numParamValues,
+ const GValue *paramValues,
+ gpointer data)
+{
+ // At least we should receive the instance emitting the signal.
+ if (numParamValues < 1)
+ return TRUE;
+
+ AtkObject* accessible = ATK_OBJECT(g_value_get_object(&paramValues[0]));
+ if (!accessible || !ATK_IS_OBJECT(accessible))
+ return TRUE;
+
+ GSignalQuery signal_query;
+ GOwnPtr<gchar> signalName;
+
+ g_signal_query(signalHint->signal_id, &signal_query);
+
+ if (!g_strcmp0(signal_query.signal_name, "state-change")) {
+ signalName.set(g_strdup_printf("state-change:%s = %d",
+ g_value_get_string(&paramValues[1]),
+ g_value_get_boolean(&paramValues[2])));
+ } else if (!g_strcmp0(signal_query.signal_name, "focus-event")) {
+ signalName.set(g_strdup_printf("focus-event = %d",
+ g_value_get_boolean(&paramValues[1])));
+ } else if (!g_strcmp0(signal_query.signal_name, "children-changed")) {
+ signalName.set(g_strdup_printf("children-changed = %d",
+ g_value_get_uint(&paramValues[1])));
+ } else
+ signalName.set(g_strdup(signal_query.signal_name));
+
+ printAccessibilityEvent(accessible, signalName.get());
+
+ return TRUE;
+}
+
+static gboolean axDocumentEventListener(GSignalInvocationHint *signalHint,
+ guint numParamValues,
+ const GValue *paramValues,
+ gpointer data)
+{
+ // At least we should receive the instance emitting the signal.
+ if (numParamValues < 1)
+ return TRUE;
+
+ AtkObject* accessible = ATK_OBJECT(g_value_get_object(&paramValues[0]));
+ if (!accessible || !ATK_IS_DOCUMENT(accessible))
+ return TRUE;
+
+ GSignalQuery signal_query;
+ g_signal_query(signalHint->signal_id, &signal_query);
+
+ printAccessibilityEvent(accessible, signal_query.signal_name);
+
+ return TRUE;
+}
+
+void connectAccessibilityCallbacks()
+{
+ // Ensure no callbacks are connected before.
+ disconnectAccessibilityCallbacks();
+
+ // Ensure that accessibility is initialized for the WebView by querying for
+ // the root accessible object, which will create the full hierarchy.
+ DumpRenderTreeSupportGtk::getRootAccessibleElement(mainFrame);
+
+ // Add global listeners for AtkObject's signals.
+ stateChangeListenerId = atk_add_global_event_listener(axObjectEventListener, "Gtk:AtkObject:state-change");
+ focusEventListenerId = atk_add_global_event_listener(axObjectEventListener, "Gtk:AtkObject:focus-event");
+ activeDescendantChangedListenerId = atk_add_global_event_listener(axObjectEventListener, "Gtk:AtkObject:active-descendant-changed");
+ childrenChangedListenerId = atk_add_global_event_listener(axObjectEventListener, "Gtk:AtkObject:children-changed");
+ propertyChangedListenerId = atk_add_global_event_listener(axObjectEventListener, "Gtk:AtkObject:property-change");
+ visibleDataChangedListenerId = atk_add_global_event_listener(axObjectEventListener, "Gtk:AtkObject:visible-data-changed");
+
+ // Ensure the Atk interface types are registered, otherwise
+ // the AtkDocument signal handlers below won't get registered.
+ GObject* dummyAxObject = G_OBJECT(g_object_new(ATK_TYPE_OBJECT, 0));
+ AtkObject* dummyNoOpAxObject = atk_no_op_object_new(dummyAxObject);
+ g_object_unref(G_OBJECT(dummyNoOpAxObject));
+ g_object_unref(dummyAxObject);
+
+ // Add global listeners for AtkDocument's signals.
+ loadCompleteListenerId = atk_add_global_event_listener(axDocumentEventListener, "Gtk:AtkDocument:load-complete");
+ loadStoppedListenerId = atk_add_global_event_listener(axDocumentEventListener, "Gtk:AtkDocument:load-stopped");
+ reloadListenerId = atk_add_global_event_listener(axDocumentEventListener, "Gtk:AtkDocument:reload");
+}
+
+void disconnectAccessibilityCallbacks()
+{
+ // AtkObject signals.
+ if (stateChangeListenerId) {
+ atk_remove_global_event_listener(stateChangeListenerId);
+ stateChangeListenerId = 0;
+ }
+ if (focusEventListenerId) {
+ atk_remove_global_event_listener(focusEventListenerId);
+ focusEventListenerId = 0;
+ }
+ if (activeDescendantChangedListenerId) {
+ atk_remove_global_event_listener(activeDescendantChangedListenerId);
+ activeDescendantChangedListenerId = 0;
+ }
+ if (childrenChangedListenerId) {
+ atk_remove_global_event_listener(childrenChangedListenerId);
+ childrenChangedListenerId = 0;
+ }
+ if (propertyChangedListenerId) {
+ atk_remove_global_event_listener(propertyChangedListenerId);
+ propertyChangedListenerId = 0;
+ }
+ if (visibleDataChangedListenerId) {
+ atk_remove_global_event_listener(visibleDataChangedListenerId);
+ visibleDataChangedListenerId = 0;
+ }
+
+ // AtkDocument signals.
+ if (loadCompleteListenerId) {
+ atk_remove_global_event_listener(loadCompleteListenerId);
+ loadCompleteListenerId = 0;
+ }
+ if (loadStoppedListenerId) {
+ atk_remove_global_event_listener(loadStoppedListenerId);
+ loadStoppedListenerId = 0;
+ }
+ if (reloadListenerId) {
+ atk_remove_global_event_listener(reloadListenerId);
+ reloadListenerId = 0;
+ }
+}
+
diff --git a/Tools/DumpRenderTree/gtk/AccessibilityCallbacks.h b/Tools/DumpRenderTree/gtk/AccessibilityCallbacks.h
new file mode 100644
index 0000000..7225757
--- /dev/null
+++ b/Tools/DumpRenderTree/gtk/AccessibilityCallbacks.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2011 Igalia S.L.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef AccessibilityCallbacks_h
+#define AccessibilityCallbacks_h
+
+void connectAccessibilityCallbacks();
+void disconnectAccessibilityCallbacks();
+
+#endif
diff --git a/Tools/DumpRenderTree/gtk/AccessibilityControllerGtk.cpp b/Tools/DumpRenderTree/gtk/AccessibilityControllerGtk.cpp
index c572633..da70efc 100644
--- a/Tools/DumpRenderTree/gtk/AccessibilityControllerGtk.cpp
+++ b/Tools/DumpRenderTree/gtk/AccessibilityControllerGtk.cpp
@@ -27,6 +27,7 @@
#include "config.h"
#include "AccessibilityController.h"
+#include "AccessibilityCallbacks.h"
#include "AccessibilityUIElement.h"
#include "DumpRenderTree.h"
#include "WebCoreSupport/DumpRenderTreeSupportGtk.h"
@@ -35,6 +36,8 @@
#include <gtk/gtk.h>
#include <webkit/webkit.h>
+static bool loggingAccessibilityEvents = false;
+
AccessibilityController::AccessibilityController()
{
}
@@ -79,6 +82,21 @@ void AccessibilityController::setLogValueChangeEvents(bool)
{
}
+void AccessibilityController::setLogAccessibilityEvents(bool logAccessibilityEvents)
+{
+ if (logAccessibilityEvents == loggingAccessibilityEvents)
+ return;
+
+ if (!logAccessibilityEvents) {
+ disconnectAccessibilityCallbacks();
+ loggingAccessibilityEvents = false;
+ return;
+ }
+
+ connectAccessibilityCallbacks();
+ loggingAccessibilityEvents = true;
+}
+
void AccessibilityController::addNotificationListener(PlatformUIElement, JSObjectRef)
{
}
diff --git a/Tools/DumpRenderTree/gtk/DumpRenderTree.cpp b/Tools/DumpRenderTree/gtk/DumpRenderTree.cpp
index ff90d81..ff3327f 100644
--- a/Tools/DumpRenderTree/gtk/DumpRenderTree.cpp
+++ b/Tools/DumpRenderTree/gtk/DumpRenderTree.cpp
@@ -39,6 +39,7 @@
#include "GOwnPtr.h"
#include "LayoutTestController.h"
#include "PixelDumpSupport.h"
+#include "TextInputController.h"
#include "WebCoreSupport/DumpRenderTreeSupportGtk.h"
#include "WorkQueue.h"
#include "WorkQueueItem.h"
@@ -419,6 +420,7 @@ static void resetDefaultsToConsistentValues()
"enable-fullscreen", TRUE,
NULL);
webkit_web_view_set_settings(webView, settings);
+ webkit_set_cache_model(WEBKIT_CACHE_MODEL_DOCUMENT_BROWSER);
DumpRenderTreeSupportGtk::clearMainFrameName(mainFrame);
@@ -432,7 +434,6 @@ static void resetDefaultsToConsistentValues()
WebKitWebBackForwardList* list = webkit_web_view_get_back_forward_list(webView);
webkit_web_back_forward_list_clear(list);
-#ifdef HAVE_LIBSOUP_2_29_90
SoupSession* session = webkit_get_default_session();
SoupCookieJar* jar = reinterpret_cast<SoupCookieJar*>(soup_session_get_feature(session, SOUP_TYPE_COOKIE_JAR));
@@ -440,11 +441,14 @@ static void resetDefaultsToConsistentValues()
// HTTP. Should we initialize it earlier, perhaps?
if (jar)
g_object_set(G_OBJECT(jar), SOUP_COOKIE_JAR_ACCEPT_POLICY, SOUP_COOKIE_JAR_ACCEPT_NO_THIRD_PARTY, NULL);
-#endif
setlocale(LC_ALL, "");
DumpRenderTreeSupportGtk::setLinksIncludedInFocusChain(true);
+ DumpRenderTreeSupportGtk::setIconDatabaseEnabled(false);
+
+ if (axController)
+ axController->resetToConsistentState();
}
static bool useLongRunningServerMode(int argc, char *argv[])
@@ -738,6 +742,11 @@ static void webViewLoadFinished(WebKitWebView* view, WebKitWebFrame* frame, void
dump();
}
+static gboolean webViewLoadError(WebKitWebView*, WebKitWebFrame*, gchar*, gpointer, gpointer)
+{
+ return TRUE; // Return true here to disable the default error page.
+}
+
static void webViewDocumentLoadFinished(WebKitWebView* view, WebKitWebFrame* frame, void*)
{
if (!done && gLayoutTestController->dumpFrameLoadCallbacks()) {
@@ -781,6 +790,11 @@ static void webViewWindowObjectCleared(WebKitWebView* view, WebKitWebFrame* fram
JSValueRef eventSender = makeEventSender(context, !webkit_web_frame_get_parent(frame));
JSObjectSetProperty(context, windowObject, eventSenderStr, eventSender, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete, 0);
JSStringRelease(eventSenderStr);
+
+ JSStringRef textInputControllerStr = JSStringCreateWithUTF8CString("textInputController");
+ JSValueRef textInputController = makeTextInputController(context);
+ JSObjectSetProperty(context, windowObject, textInputControllerStr, textInputController, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete, 0);
+ JSStringRelease(textInputControllerStr);
}
static gboolean webViewConsoleMessage(WebKitWebView* view, const gchar* message, unsigned int line, const gchar* sourceId, gpointer data)
@@ -999,6 +1013,7 @@ static WebKitWebView* createWebView()
g_object_connect(G_OBJECT(view),
"signal::load-started", webViewLoadStarted, 0,
"signal::load-finished", webViewLoadFinished, 0,
+ "signal::load-error", webViewLoadError, 0,
"signal::window-object-cleared", webViewWindowObjectCleared, 0,
"signal::console-message", webViewConsoleMessage, 0,
"signal::script-alert", webViewScriptAlert, 0,
diff --git a/Tools/DumpRenderTree/gtk/EventSender.cpp b/Tools/DumpRenderTree/gtk/EventSender.cpp
index 923a4ba..10e129c 100644
--- a/Tools/DumpRenderTree/gtk/EventSender.cpp
+++ b/Tools/DumpRenderTree/gtk/EventSender.cpp
@@ -240,33 +240,42 @@ static void updateClickCount(int button)
clickCount++;
}
+static guint gdkModifierFromJSValue(JSContextRef context, const JSValueRef value)
+{
+ JSStringRef string = JSValueToStringCopy(context, value, 0);
+ guint gdkModifier = 0;
+ if (JSStringIsEqualToUTF8CString(string, "ctrlKey")
+ || JSStringIsEqualToUTF8CString(string, "addSelectionKey"))
+ gdkModifier = GDK_CONTROL_MASK;
+ else if (JSStringIsEqualToUTF8CString(string, "shiftKey")
+ || JSStringIsEqualToUTF8CString(string, "rangeSelectionKey"))
+ gdkModifier = GDK_SHIFT_MASK;
+ else if (JSStringIsEqualToUTF8CString(string, "altKey"))
+ gdkModifier = GDK_MOD1_MASK;
+
+ // Currently the metaKey as defined in WebCore/platform/gtk/MouseEventGtk.cpp
+ // is GDK_MOD2_MASK. This code must be kept in sync with that file.
+ else if (JSStringIsEqualToUTF8CString(string, "metaKey"))
+ gdkModifier = GDK_MOD2_MASK;
+
+ JSStringRelease(string);
+ return gdkModifier;
+}
+
static guint gdkModifersFromJSValue(JSContextRef context, const JSValueRef modifiers)
{
+ // The value may either be a string with a single modifier or an array of modifiers.
+ if (JSValueIsString(context, modifiers))
+ return gdkModifierFromJSValue(context, modifiers);
+
JSObjectRef modifiersArray = JSValueToObject(context, modifiers, 0);
if (!modifiersArray)
return 0;
guint gdkModifiers = 0;
int modifiersCount = JSValueToNumber(context, JSObjectGetProperty(context, modifiersArray, JSStringCreateWithUTF8CString("length"), 0), 0);
- for (int i = 0; i < modifiersCount; ++i) {
- JSValueRef value = JSObjectGetPropertyAtIndex(context, modifiersArray, i, 0);
- JSStringRef string = JSValueToStringCopy(context, value, 0);
- if (JSStringIsEqualToUTF8CString(string, "ctrlKey")
- || JSStringIsEqualToUTF8CString(string, "addSelectionKey"))
- gdkModifiers |= GDK_CONTROL_MASK;
- else if (JSStringIsEqualToUTF8CString(string, "shiftKey")
- || JSStringIsEqualToUTF8CString(string, "rangeSelectionKey"))
- gdkModifiers |= GDK_SHIFT_MASK;
- else if (JSStringIsEqualToUTF8CString(string, "altKey"))
- gdkModifiers |= GDK_MOD1_MASK;
-
- // Currently the metaKey as defined in WebCore/platform/gtk/MouseEventGtk.cpp
- // is GDK_MOD2_MASK. This code must be kept in sync with that file.
- else if (JSStringIsEqualToUTF8CString(string, "metaKey"))
- gdkModifiers |= GDK_MOD2_MASK;
-
- JSStringRelease(string);
- }
+ for (int i = 0; i < modifiersCount; ++i)
+ gdkModifiers |= gdkModifierFromJSValue(context, JSObjectGetPropertyAtIndex(context, modifiersArray, i, 0));
return gdkModifiers;
}
diff --git a/Tools/DumpRenderTree/gtk/LayoutTestControllerGtk.cpp b/Tools/DumpRenderTree/gtk/LayoutTestControllerGtk.cpp
index 1527811..56d75f7 100644
--- a/Tools/DumpRenderTree/gtk/LayoutTestControllerGtk.cpp
+++ b/Tools/DumpRenderTree/gtk/LayoutTestControllerGtk.cpp
@@ -3,7 +3,7 @@
* Copyright (C) 2007 Eric Seidel <eric@webkit.org>
* Copyright (C) 2008 Nuanti Ltd.
* Copyright (C) 2009 Jan Michael Alonzo <jmalonzo@gmail.com>
- * Copyright (C) 2009 Collabora Ltd.
+ * Copyright (C) 2009,2011 Collabora Ltd.
* Copyright (C) 2010 Joone Hur <joone@kldp.org>
*
* Redistribution and use in source and binary forms, with or without
@@ -230,7 +230,6 @@ void LayoutTestController::setAcceptsEditing(bool acceptsEditing)
void LayoutTestController::setAlwaysAcceptCookies(bool alwaysAcceptCookies)
{
-#ifdef HAVE_LIBSOUP_2_29_90
SoupSession* session = webkit_get_default_session();
SoupCookieJar* jar = reinterpret_cast<SoupCookieJar*>(soup_session_get_feature(session, SOUP_TYPE_COOKIE_JAR));
@@ -251,7 +250,6 @@ void LayoutTestController::setAlwaysAcceptCookies(bool alwaysAcceptCookies)
policy = SOUP_COOKIE_JAR_ACCEPT_NO_THIRD_PARTY;
g_object_set(G_OBJECT(jar), SOUP_COOKIE_JAR_ACCEPT_POLICY, policy, NULL);
-#endif
}
void LayoutTestController::setCustomPolicyDelegate(bool setDelegate, bool permissive)
@@ -492,9 +490,9 @@ void LayoutTestController::addMockSpeechInputResult(JSStringRef result, double c
// See https://bugs.webkit.org/show_bug.cgi?id=39485.
}
-void LayoutTestController::setIconDatabaseEnabled(bool flag)
+void LayoutTestController::setIconDatabaseEnabled(bool enabled)
{
- // FIXME: implement
+ DumpRenderTreeSupportGtk::setIconDatabaseEnabled(enabled);
}
void LayoutTestController::setJavaScriptProfilingEnabled(bool flag)
@@ -546,10 +544,42 @@ void LayoutTestController::execCommand(JSStringRef name, JSStringRef value)
g_free(cValue);
}
-bool LayoutTestController::findString(JSContextRef /* context */, JSStringRef /* target */, JSObjectRef /* optionsArray */)
+bool LayoutTestController::findString(JSContextRef context, JSStringRef target, JSObjectRef optionsArray)
{
- // FIXME: Implement
- return false;
+ WebKitFindOptions findOptions = 0;
+ WebKitWebView* webView = webkit_web_frame_get_web_view(mainFrame);
+ ASSERT(webView);
+
+ JSRetainPtr<JSStringRef> lengthPropertyName(Adopt, JSStringCreateWithUTF8CString("length"));
+ JSValueRef lengthValue = JSObjectGetProperty(context, optionsArray, lengthPropertyName.get(), 0);
+ if (!JSValueIsNumber(context, lengthValue))
+ return false;
+
+ GOwnPtr<gchar> targetString(JSStringCopyUTF8CString(target));
+
+ size_t length = static_cast<size_t>(JSValueToNumber(context, lengthValue, 0));
+ for (size_t i = 0; i < length; ++i) {
+ JSValueRef value = JSObjectGetPropertyAtIndex(context, optionsArray, i, 0);
+ if (!JSValueIsString(context, value))
+ continue;
+
+ JSRetainPtr<JSStringRef> optionName(Adopt, JSValueToStringCopy(context, value, 0));
+
+ if (JSStringIsEqualToUTF8CString(optionName.get(), "CaseInsensitive"))
+ findOptions |= WebKit::WebFindOptionsCaseInsensitive;
+ else if (JSStringIsEqualToUTF8CString(optionName.get(), "AtWordStarts"))
+ findOptions |= WebKit::WebFindOptionsAtWordStarts;
+ else if (JSStringIsEqualToUTF8CString(optionName.get(), "TreatMedialCapitalAsWordStart"))
+ findOptions |= WebKit::WebFindOptionsTreatMedialCapitalAsWordStart;
+ else if (JSStringIsEqualToUTF8CString(optionName.get(), "Backwards"))
+ findOptions |= WebKit::WebFindOptionsBackwards;
+ else if (JSStringIsEqualToUTF8CString(optionName.get(), "WrapAround"))
+ findOptions |= WebKit::WebFindOptionsWrapAround;
+ else if (JSStringIsEqualToUTF8CString(optionName.get(), "StartInSelection"))
+ findOptions |= WebKit::WebFindOptionsStartInSelection;
+ }
+
+ return DumpRenderTreeSupportGtk::findString(webView, targetString.get(), findOptions);
}
bool LayoutTestController::isCommandEnabled(JSStringRef name)
@@ -565,10 +595,20 @@ bool LayoutTestController::isCommandEnabled(JSStringRef name)
void LayoutTestController::setCacheModel(int cacheModel)
{
- if (!cacheModel) // WebCacheModelDocumentViewer
- webkit_set_cache_model(WEBKIT_CACHE_MODEL_DOCUMENT_VIEWER);
- else
- webkit_set_cache_model(WEBKIT_CACHE_MODEL_WEB_BROWSER);
+ // These constants are derived from the Mac cache model enum in Source/WebKit/mac/WebView/WebPreferences.h.
+ switch (cacheModel) {
+ case 0:
+ webkit_set_cache_model(WEBKIT_CACHE_MODEL_DOCUMENT_VIEWER);
+ break;
+ case 1:
+ webkit_set_cache_model(WEBKIT_CACHE_MODEL_DOCUMENT_BROWSER);
+ break;
+ case 3:
+ webkit_set_cache_model(WEBKIT_CACHE_MODEL_DOCUMENT_BROWSER);
+ break;
+ default:
+ ASSERT_NOT_REACHED();
+ }
}
void LayoutTestController::setPersistentUserStyleSheetLocation(JSStringRef jsURL)
diff --git a/Tools/DumpRenderTree/gtk/PixelDumpSupportGtk.cpp b/Tools/DumpRenderTree/gtk/PixelDumpSupportGtk.cpp
index 32bc600..1e591bb 100644
--- a/Tools/DumpRenderTree/gtk/PixelDumpSupportGtk.cpp
+++ b/Tools/DumpRenderTree/gtk/PixelDumpSupportGtk.cpp
@@ -37,13 +37,14 @@
PassRefPtr<BitmapContext> createBitmapContextFromWebView(bool, bool, bool, bool)
{
WebKitWebView* view = webkit_web_frame_get_web_view(mainFrame);
+ GtkWidget* viewContainer = gtk_widget_get_parent(GTK_WIDGET(view));
gint width, height;
#ifdef GTK_API_VERSION_2
- GdkPixmap* pixmap = gtk_widget_get_snapshot(GTK_WIDGET(view), 0);
+ GdkPixmap* pixmap = gtk_widget_get_snapshot(viewContainer, 0);
gdk_pixmap_get_size(pixmap, &width, &height);
#else
- width = gtk_widget_get_allocated_width(GTK_WIDGET(view));
- height = gtk_widget_get_allocated_height(GTK_WIDGET(view));
+ width = gtk_widget_get_allocated_width(viewContainer);
+ height = gtk_widget_get_allocated_height(viewContainer);
#endif
cairo_surface_t* imageSurface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, width, height);
@@ -53,7 +54,7 @@ PassRefPtr<BitmapContext> createBitmapContextFromWebView(bool, bool, bool, bool)
cairo_paint(context);
g_object_unref(pixmap);
#else
- gtk_widget_draw(GTK_WIDGET(view), context);
+ gtk_widget_draw(viewContainer, context);
#endif
return BitmapContext::createByAdoptingBitmapAndContext(0, context);
diff --git a/Tools/DumpRenderTree/gtk/TextInputController.cpp b/Tools/DumpRenderTree/gtk/TextInputController.cpp
new file mode 100644
index 0000000..7243fdc
--- /dev/null
+++ b/Tools/DumpRenderTree/gtk/TextInputController.cpp
@@ -0,0 +1,177 @@
+/*
+ * Copyright (C) 2011 Igalia S.L.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "TextInputController.h"
+
+#include "DumpRenderTree.h"
+#include "WebCoreSupport/DumpRenderTreeSupportGtk.h"
+#include <GOwnPtrGtk.h>
+#include <JavaScriptCore/JSObjectRef.h>
+#include <JavaScriptCore/JSRetainPtr.h>
+#include <JavaScriptCore/JSStringRef.h>
+#include <cstring>
+
+static JSValueRef setMarkedTextCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ WebKitWebView* view = webkit_web_frame_get_web_view(mainFrame);
+ if (!view)
+ return JSValueMakeUndefined(context);
+
+ if (argumentCount < 3)
+ return JSValueMakeUndefined(context);
+
+ JSStringRef string = JSValueToStringCopy(context, arguments[0], exception);
+ g_return_val_if_fail((!exception || !*exception), JSValueMakeUndefined(context));
+
+ size_t bufferSize = JSStringGetMaximumUTF8CStringSize(string);
+ GOwnPtr<gchar> stringBuffer(static_cast<gchar*>(g_malloc(bufferSize)));
+ JSStringGetUTF8CString(string, stringBuffer.get(), bufferSize);
+ JSStringRelease(string);
+
+ int start = static_cast<int>(JSValueToNumber(context, arguments[1], exception));
+ g_return_val_if_fail((!exception || !*exception), JSValueMakeUndefined(context));
+
+ int end = static_cast<int>(JSValueToNumber(context, arguments[2], exception));
+ g_return_val_if_fail((!exception || !*exception), JSValueMakeUndefined(context));
+
+ DumpRenderTreeSupportGtk::setComposition(view, stringBuffer.get(), start, end);
+
+ return JSValueMakeUndefined(context);
+}
+
+static JSValueRef insertTextCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ WebKitWebView* view = webkit_web_frame_get_web_view(mainFrame);
+ if (!view)
+ return JSValueMakeUndefined(context);
+
+ if (argumentCount < 1)
+ return JSValueMakeUndefined(context);
+
+ JSStringRef string = JSValueToStringCopy(context, arguments[0], exception);
+ g_return_val_if_fail((!exception || !*exception), JSValueMakeUndefined(context));
+
+ size_t bufferSize = JSStringGetMaximumUTF8CStringSize(string);
+ GOwnPtr<gchar> stringBuffer(static_cast<gchar*>(g_malloc(bufferSize)));
+ JSStringGetUTF8CString(string, stringBuffer.get(), bufferSize);
+ JSStringRelease(string);
+
+ DumpRenderTreeSupportGtk::confirmComposition(view, stringBuffer.get());
+
+ return JSValueMakeUndefined(context);
+}
+
+static JSValueRef unmarkTextCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ WebKitWebView* view = webkit_web_frame_get_web_view(mainFrame);
+ if (!view)
+ return JSValueMakeUndefined(context);
+
+ DumpRenderTreeSupportGtk::confirmComposition(view, 0);
+ return JSValueMakeUndefined(context);
+}
+
+static JSValueRef firstRectForCharacterRangeCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ WebKitWebView* view = webkit_web_frame_get_web_view(mainFrame);
+ if (!view)
+ return JSValueMakeUndefined(context);
+
+ if (argumentCount < 2)
+ return JSValueMakeUndefined(context);
+
+ int location = static_cast<int>(JSValueToNumber(context, arguments[0], exception));
+ g_return_val_if_fail((!exception || !*exception), JSValueMakeUndefined(context));
+
+ int length = static_cast<int>(JSValueToNumber(context, arguments[1], exception));
+ g_return_val_if_fail((!exception || !*exception), JSValueMakeUndefined(context));
+
+ GdkRectangle rect;
+ if (!DumpRenderTreeSupportGtk::firstRectForCharacterRange(view, location, length, &rect))
+ return JSValueMakeUndefined(context);
+
+ JSValueRef arrayValues[4];
+ arrayValues[0] = JSValueMakeNumber(context, rect.x);
+ arrayValues[1] = JSValueMakeNumber(context, rect.y);
+ arrayValues[2] = JSValueMakeNumber(context, rect.width);
+ arrayValues[3] = JSValueMakeNumber(context, rect.height);
+ JSObjectRef arrayObject = JSObjectMakeArray(context, 4, arrayValues, exception);
+ g_return_val_if_fail((!exception || !*exception), JSValueMakeUndefined(context));
+
+ return arrayObject;
+}
+
+static JSValueRef selectedRangeCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ WebKitWebView* view = webkit_web_frame_get_web_view(mainFrame);
+ if (!view)
+ return JSValueMakeUndefined(context);
+
+ int start, end;
+ if (!DumpRenderTreeSupportGtk::selectedRange(view, &start, &end))
+ return JSValueMakeUndefined(context);
+
+ JSValueRef arrayValues[2];
+ arrayValues[0] = JSValueMakeNumber(context, start);
+ arrayValues[1] = JSValueMakeNumber(context, end);
+ JSObjectRef arrayObject = JSObjectMakeArray(context, 2, arrayValues, exception);
+ g_return_val_if_fail((!exception || !*exception), JSValueMakeUndefined(context));
+
+ return arrayObject;
+}
+
+static JSStaticFunction staticFunctions[] = {
+ { "setMarkedText", setMarkedTextCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "insertText", insertTextCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "unmarkText", unmarkTextCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "firstRectForCharacterRange", firstRectForCharacterRangeCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "selectedRange", selectedRangeCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { 0, 0, 0 }
+};
+
+static JSClassRef getClass(JSContextRef context)
+{
+ static JSClassRef textInputControllerClass = 0;
+
+ if (!textInputControllerClass) {
+ JSClassDefinition classDefinition = {
+ 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+ classDefinition.staticFunctions = staticFunctions;
+
+ textInputControllerClass = JSClassCreate(&classDefinition);
+ }
+
+ return textInputControllerClass;
+}
+
+JSObjectRef makeTextInputController(JSContextRef context)
+{
+ return JSObjectMake(context, getClass(context), 0);
+}
diff --git a/Tools/DumpRenderTree/gtk/TextInputController.h b/Tools/DumpRenderTree/gtk/TextInputController.h
new file mode 100644
index 0000000..53793f6
--- /dev/null
+++ b/Tools/DumpRenderTree/gtk/TextInputController.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2011 Igalia S.L.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef TextInputController_h
+#define TextInputController_h
+
+typedef const struct OpaqueJSContext* JSContextRef;
+typedef struct OpaqueJSValue* JSObjectRef;
+
+JSObjectRef makeTextInputController(JSContextRef);
+
+#endif
diff --git a/Tools/DumpRenderTree/mac/AccessibilityControllerMac.mm b/Tools/DumpRenderTree/mac/AccessibilityControllerMac.mm
index 1a9f9c9..d41f01d 100644
--- a/Tools/DumpRenderTree/mac/AccessibilityControllerMac.mm
+++ b/Tools/DumpRenderTree/mac/AccessibilityControllerMac.mm
@@ -74,6 +74,10 @@ void AccessibilityController::setLogValueChangeEvents(bool)
{
}
+void AccessibilityController::setLogAccessibilityEvents(bool)
+{
+}
+
void AccessibilityController::addNotificationListener(PlatformUIElement, JSObjectRef)
{
}
diff --git a/Tools/DumpRenderTree/mac/DumpRenderTree.mm b/Tools/DumpRenderTree/mac/DumpRenderTree.mm
index ed09cf6..eab3742 100644
--- a/Tools/DumpRenderTree/mac/DumpRenderTree.mm
+++ b/Tools/DumpRenderTree/mac/DumpRenderTree.mm
@@ -448,6 +448,7 @@ static void resetDefaultsToConsistentValues()
[preferences setDeveloperExtrasEnabled:NO];
[preferences setLoadsImagesAutomatically:YES];
[preferences setFrameFlatteningEnabled:NO];
+ [preferences setSpatialNavigationEnabled:NO];
[preferences setEditingBehavior:WebKitEditingMacBehavior];
if (persistentUserStyleSheetLocation) {
[preferences setUserStyleSheetLocation:[NSURL URLWithString:(NSString *)(persistentUserStyleSheetLocation.get())]];
@@ -753,7 +754,10 @@ static void dumpHistoryItem(WebHistoryItem *item, int indent, BOOL current)
static void dumpFrameScrollPosition(WebFrame *f)
{
- NSPoint scrollPosition = [[[[f frameView] documentView] superview] bounds].origin;
+ WebScriptObject* scriptObject = [f windowObject];
+ NSPoint scrollPosition = NSMakePoint(
+ [[scriptObject valueForKey:@"pageXOffset"] floatValue],
+ [[scriptObject valueForKey:@"pageYOffset"] floatValue]);
if (ABS(scrollPosition.x) > 0.00000001 || ABS(scrollPosition.y) > 0.00000001) {
if ([f parentFrame] != nil)
printf("frame '%s' ", [[f name] UTF8String]);
diff --git a/Tools/DumpRenderTree/pthreads/JavaScriptThreadingPthreads.cpp b/Tools/DumpRenderTree/pthreads/JavaScriptThreadingPthreads.cpp
index 5a48b27..1266c02 100644
--- a/Tools/DumpRenderTree/pthreads/JavaScriptThreadingPthreads.cpp
+++ b/Tools/DumpRenderTree/pthreads/JavaScriptThreadingPthreads.cpp
@@ -37,6 +37,8 @@
#include <wtf/Assertions.h>
#include <wtf/HashSet.h>
+static JSContextGroupRef javaScriptThreadsGroup;
+
static pthread_mutex_t javaScriptThreadsMutex = PTHREAD_MUTEX_INITIALIZER;
static bool javaScriptThreadsShouldTerminate;
@@ -51,58 +53,68 @@ static ThreadSet* javaScriptThreads()
return &staticJavaScriptThreads;
}
-// Loops forever, running a script and randomly respawning, until
-// javaScriptThreadsShouldTerminate becomes true.
+// This function exercises JSC in a loop until javaScriptThreadsShouldTerminate
+// becomes true or it probabilistically decides to spawn a replacement thread and exit.
void* runJavaScriptThread(void* arg)
{
- const char* const script =
+ static const char* const script =
"var array = [];"
- "for (var i = 0; i < 10; i++) {"
+ "for (var i = 0; i < 1024; i++) {"
" array.push(String(i));"
"}";
- while (1) {
- JSGlobalContextRef ctx = JSGlobalContextCreate(0);
- JSStringRef scriptRef = JSStringCreateWithUTF8CString(script);
+ pthread_mutex_lock(&javaScriptThreadsMutex);
+ JSGlobalContextRef ctx = JSGlobalContextCreateInGroup(javaScriptThreadsGroup, 0);
+ pthread_mutex_unlock(&javaScriptThreadsMutex);
+
+ pthread_mutex_lock(&javaScriptThreadsMutex);
+ JSStringRef scriptRef = JSStringCreateWithUTF8CString(script);
+ pthread_mutex_unlock(&javaScriptThreadsMutex);
+ while (1) {
+ pthread_mutex_lock(&javaScriptThreadsMutex);
JSValueRef exception = 0;
JSEvaluateScript(ctx, scriptRef, 0, 0, 1, &exception);
ASSERT(!exception);
-
- JSGarbageCollect(ctx);
- JSGlobalContextRelease(ctx);
- JSStringRelease(scriptRef);
-
- JSGarbageCollect(0);
+ pthread_mutex_unlock(&javaScriptThreadsMutex);
pthread_mutex_lock(&javaScriptThreadsMutex);
+ size_t valuesCount = 1024;
+ JSValueRef values[valuesCount];
+ for (size_t i = 0; i < valuesCount; ++i)
+ values[i] = JSObjectMake(ctx, 0, 0);
+ pthread_mutex_unlock(&javaScriptThreadsMutex);
// Check for cancellation.
- if (javaScriptThreadsShouldTerminate) {
- javaScriptThreads()->remove(pthread_self());
- pthread_mutex_unlock(&javaScriptThreadsMutex);
- return 0;
- }
+ if (javaScriptThreadsShouldTerminate)
+ goto done;
// Respawn probabilistically.
if (random() % 5 == 0) {
+ pthread_mutex_lock(&javaScriptThreadsMutex);
pthread_t pthread;
pthread_create(&pthread, 0, &runJavaScriptThread, 0);
pthread_detach(pthread);
-
- javaScriptThreads()->remove(pthread_self());
javaScriptThreads()->add(pthread);
-
pthread_mutex_unlock(&javaScriptThreadsMutex);
- return 0;
+ goto done;
}
-
- pthread_mutex_unlock(&javaScriptThreadsMutex);
}
+
+done:
+ pthread_mutex_lock(&javaScriptThreadsMutex);
+ JSStringRelease(scriptRef);
+ JSGarbageCollect(ctx);
+ JSGlobalContextRelease(ctx);
+ javaScriptThreads()->remove(pthread_self());
+ pthread_mutex_unlock(&javaScriptThreadsMutex);
+ return 0;
}
void startJavaScriptThreads()
{
+ javaScriptThreadsGroup = JSContextGroupCreate();
+
pthread_mutex_lock(&javaScriptThreadsMutex);
for (int i = 0; i < javaScriptThreadsCount; i++) {
@@ -121,8 +133,6 @@ void stopJavaScriptThreads()
javaScriptThreadsShouldTerminate = true;
- ASSERT(javaScriptThreads()->size() == javaScriptThreadsCount);
-
pthread_mutex_unlock(&javaScriptThreadsMutex);
while (true) {
diff --git a/Tools/DumpRenderTree/qt/DumpRenderTree.pro b/Tools/DumpRenderTree/qt/DumpRenderTree.pro
index a7c6c26..d84af96 100644
--- a/Tools/DumpRenderTree/qt/DumpRenderTree.pro
+++ b/Tools/DumpRenderTree/qt/DumpRenderTree.pro
@@ -5,12 +5,12 @@ CONFIG += uitools
BASEDIR = $$PWD/../
isEmpty(OUTPUT_DIR): OUTPUT_DIR = ../../..
-include(../../../WebKit.pri)
+include(../../../Source/WebKit.pri)
INCLUDEPATH += ../../../Source
INCLUDEPATH += ../../../Source/JavaScriptCore
INCLUDEPATH += ../../../Source/JavaScriptCore/ForwardingHeaders
INCLUDEPATH += $$BASEDIR
-DESTDIR = ../../../bin
+DESTDIR = ../../bin
unix:!mac:!symbian {
CONFIG += link_pkgconfig
diff --git a/Tools/DumpRenderTree/qt/DumpRenderTreeQt.cpp b/Tools/DumpRenderTree/qt/DumpRenderTreeQt.cpp
index ce608cc..7d20f47 100644
--- a/Tools/DumpRenderTree/qt/DumpRenderTreeQt.cpp
+++ b/Tools/DumpRenderTree/qt/DumpRenderTreeQt.cpp
@@ -83,6 +83,8 @@
namespace WebCore {
+const int databaseDefaultQuota = 5 * 1024 * 1024;
+
NetworkAccessManager::NetworkAccessManager(QObject* parent)
: QNetworkAccessManager(parent)
{
@@ -520,7 +522,7 @@ void DumpRenderTree::dryRunPrint(QWebFrame* frame)
#endif
}
-void DumpRenderTree::resetToConsistentStateBeforeTesting()
+void DumpRenderTree::resetToConsistentStateBeforeTesting(const QUrl& url)
{
// reset so that any current loads are stopped
// NOTE: that this has to be done before the layoutTestController is
@@ -529,6 +531,10 @@ void DumpRenderTree::resetToConsistentStateBeforeTesting()
m_page->triggerAction(QWebPage::Stop);
m_page->blockSignals(false);
+ QList<QWebSecurityOrigin> knownOrigins = QWebSecurityOrigin::allOrigins();
+ for (int i = 0; i < knownOrigins.size(); ++i)
+ knownOrigins[i].setDatabaseQuota(databaseDefaultQuota);
+
// reset the layoutTestController at this point, so that we under no
// circumstance dump (stop the waitUntilDone timer) during the reset
// of the DRT.
@@ -550,6 +556,14 @@ void DumpRenderTree::resetToConsistentStateBeforeTesting()
m_page->mainFrame()->setScrollBarPolicy(Qt::Vertical, Qt::ScrollBarAsNeeded);
m_page->mainFrame()->setScrollBarPolicy(Qt::Horizontal, Qt::ScrollBarAsNeeded);
+ if (url.scheme() == "http" || url.scheme() == "https") {
+ // credentials may exist from previous tests.
+ m_page->setNetworkAccessManager(0);
+ delete m_networkAccessManager;
+ m_networkAccessManager = new NetworkAccessManager(this);
+ m_page->setNetworkAccessManager(m_networkAccessManager);
+ }
+
WorkQueue::shared()->clear();
WorkQueue::shared()->setFrozen(false);
@@ -560,6 +574,7 @@ void DumpRenderTree::resetToConsistentStateBeforeTesting()
QLocale::setDefault(QLocale::c());
+ layoutTestController()->setDeveloperExtrasEnabled(true);
#ifndef Q_OS_WINCE
setlocale(LC_ALL, "");
#endif
@@ -579,26 +594,16 @@ static bool isWebInspectorTest(const QUrl& url)
return false;
}
-static bool shouldEnableDeveloperExtras(const QUrl& url)
-{
- return true;
-}
-
void DumpRenderTree::open(const QUrl& url)
{
DumpRenderTreeSupportQt::dumpResourceLoadCallbacksPath(QFileInfo(url.toString()).path());
- resetToConsistentStateBeforeTesting();
+ resetToConsistentStateBeforeTesting(url);
- if (shouldEnableDeveloperExtras(m_page->mainFrame()->url())) {
+ if (isWebInspectorTest(m_page->mainFrame()->url()))
layoutTestController()->closeWebInspector();
- layoutTestController()->setDeveloperExtrasEnabled(false);
- }
- if (shouldEnableDeveloperExtras(url)) {
- layoutTestController()->setDeveloperExtrasEnabled(true);
- if (isWebInspectorTest(url))
- layoutTestController()->showWebInspector();
- }
+ if (isWebInspectorTest(url))
+ layoutTestController()->showWebInspector();
if (isGlobalHistoryTest(url))
layoutTestController()->dumpHistoryCallbacks();
@@ -1028,7 +1033,7 @@ void DumpRenderTree::dumpDatabaseQuota(QWebFrame* frame, const QString& dbName)
origin.host().toUtf8().data(),
origin.port(),
dbName.toUtf8().data());
- origin.setDatabaseQuota(5 * 1024 * 1024);
+ origin.setDatabaseQuota(databaseDefaultQuota);
}
void DumpRenderTree::dumpApplicationCacheQuota(QWebSecurityOrigin* origin, quint64 defaultOriginQuota)
@@ -1085,9 +1090,6 @@ void DumpRenderTree::windowCloseRequested()
QWebPage* page = qobject_cast<QWebPage*>(sender());
QObject* container = page->parent();
windows.removeAll(container);
- // Our use of container->deleteLater() means we need to remove closed pages
- // from the org.webkit.qt.DumpRenderTree group explicitly.
- DumpRenderTreeSupportQt::webPageSetGroupName(page, "");
container->deleteLater();
}
diff --git a/Tools/DumpRenderTree/qt/DumpRenderTreeQt.h b/Tools/DumpRenderTree/qt/DumpRenderTreeQt.h
index 8cb5efb..5b53cd9 100644
--- a/Tools/DumpRenderTree/qt/DumpRenderTreeQt.h
+++ b/Tools/DumpRenderTree/qt/DumpRenderTreeQt.h
@@ -86,7 +86,7 @@ public:
void setDumpPixels(bool);
void closeRemainingWindows();
- void resetToConsistentStateBeforeTesting();
+ void resetToConsistentStateBeforeTesting(const QUrl&);
LayoutTestController *layoutTestController() const { return m_controller; }
EventSender *eventSender() const { return m_eventSender; }
diff --git a/Tools/DumpRenderTree/qt/EventSenderQt.cpp b/Tools/DumpRenderTree/qt/EventSenderQt.cpp
index 6fb75a5..6449484 100644
--- a/Tools/DumpRenderTree/qt/EventSenderQt.cpp
+++ b/Tools/DumpRenderTree/qt/EventSenderQt.cpp
@@ -360,7 +360,7 @@ void EventSender::keyDown(const QString& string, const QStringList& modifiers, u
sendEvent(m_page, &event2);
}
-void EventSender::contextClick()
+QStringList EventSender::contextClick()
{
QMouseEvent event(QEvent::MouseButtonPress, m_mousePos, Qt::RightButton, Qt::RightButton, Qt::NoModifier);
sendEvent(m_page, &event);
@@ -378,6 +378,7 @@ void EventSender::contextClick()
QContextMenuEvent ctxEvent(QContextMenuEvent::Mouse, m_mousePos);
sendEvent(m_page->view(), &ctxEvent);
}
+ return DumpRenderTreeSupportQt::contextMenu(m_page);
}
void EventSender::scheduleAsynchronousClick()
diff --git a/Tools/DumpRenderTree/qt/EventSenderQt.h b/Tools/DumpRenderTree/qt/EventSenderQt.h
index 4ba8382..ecb06e2 100644
--- a/Tools/DumpRenderTree/qt/EventSenderQt.h
+++ b/Tools/DumpRenderTree/qt/EventSenderQt.h
@@ -65,7 +65,7 @@ public slots:
void leapForward(int ms);
void keyDown(const QString& string, const QStringList& modifiers = QStringList(), unsigned int location = 0);
void clearKillRing() {}
- void contextClick();
+ QStringList contextClick();
void scheduleAsynchronousClick();
void addTouchPoint(int x, int y);
void updateTouchPoint(int index, int x, int y);
diff --git a/Tools/DumpRenderTree/qt/ImageDiff.pro b/Tools/DumpRenderTree/qt/ImageDiff.pro
index a218449..cdb067e 100644
--- a/Tools/DumpRenderTree/qt/ImageDiff.pro
+++ b/Tools/DumpRenderTree/qt/ImageDiff.pro
@@ -2,7 +2,7 @@ TARGET = ImageDiff
CONFIG -= app_bundle
isEmpty(OUTPUT_DIR): OUTPUT_DIR = ../../..
-include(../../../WebKit.pri)
+include(../../../Source/WebKit.pri)
INCLUDEPATH += ../../../Source/JavaScriptCore
DESTDIR = $$OUTPUT_DIR/bin
diff --git a/Tools/DumpRenderTree/qt/LayoutTestControllerQt.cpp b/Tools/DumpRenderTree/qt/LayoutTestControllerQt.cpp
index 56406c2..a11bc60 100644
--- a/Tools/DumpRenderTree/qt/LayoutTestControllerQt.cpp
+++ b/Tools/DumpRenderTree/qt/LayoutTestControllerQt.cpp
@@ -87,6 +87,7 @@ void LayoutTestController::reset()
DumpRenderTreeSupportQt::dumpHistoryCallbacks(false);
DumpRenderTreeSupportQt::dumpVisitedLinksCallbacks(false);
setIconDatabaseEnabled(false);
+ clearAllDatabases();
emit hidePage();
}
@@ -830,5 +831,10 @@ QVariantList LayoutTestController::nodesFromRect(const QWebElement& document, in
return DumpRenderTreeSupportQt::nodesFromRect(document, x, y, top, right, bottom, left, ignoreClipping);
}
+void LayoutTestController::addURLToRedirect(const QString& origin, const QString& destination)
+{
+ DumpRenderTreeSupportQt::addURLToRedirect(origin, destination);
+}
+
const unsigned LayoutTestController::maxViewWidth = 800;
const unsigned LayoutTestController::maxViewHeight = 600;
diff --git a/Tools/DumpRenderTree/qt/LayoutTestControllerQt.h b/Tools/DumpRenderTree/qt/LayoutTestControllerQt.h
index 0048a7e..bc62c51 100644
--- a/Tools/DumpRenderTree/qt/LayoutTestControllerQt.h
+++ b/Tools/DumpRenderTree/qt/LayoutTestControllerQt.h
@@ -230,6 +230,8 @@ public slots:
QVariantList nodesFromRect(const QWebElement& document, int x, int y, unsigned top, unsigned right, unsigned bottom, unsigned left, bool ignoreClipping);
+ void addURLToRedirect(const QString& origin, const QString& destination);
+
/*
Policy values: 'on', 'auto' or 'off'.
Orientation values: 'vertical' or 'horizontal'.
diff --git a/Tools/DumpRenderTree/qt/TestNetscapePlugin/TestNetscapePlugin.pro b/Tools/DumpRenderTree/qt/TestNetscapePlugin/TestNetscapePlugin.pro
index 6f96d0a..176c4c4 100644
--- a/Tools/DumpRenderTree/qt/TestNetscapePlugin/TestNetscapePlugin.pro
+++ b/Tools/DumpRenderTree/qt/TestNetscapePlugin/TestNetscapePlugin.pro
@@ -3,7 +3,7 @@ TARGET = TestNetscapePlugIn
VPATH = ../../unix/TestNetscapePlugin ../../TestNetscapePlugIn
isEmpty(OUTPUT_DIR): OUTPUT_DIR = ../../../..
-include(../../../../WebKit.pri)
+include(../../../../Source/WebKit.pri)
DESTDIR = $$OUTPUT_DIR/lib/plugins
diff --git a/Tools/DumpRenderTree/unix/TestNetscapePlugin/TestNetscapePlugin.cpp b/Tools/DumpRenderTree/unix/TestNetscapePlugin/TestNetscapePlugin.cpp
index 2f7288a..4936efd 100644
--- a/Tools/DumpRenderTree/unix/TestNetscapePlugin/TestNetscapePlugin.cpp
+++ b/Tools/DumpRenderTree/unix/TestNetscapePlugin/TestNetscapePlugin.cpp
@@ -79,6 +79,9 @@ webkit_test_plugin_new_instance(NPMIMEType mimetype,
else if (strcasecmp(argn[i], "src") == 0 &&
strcasecmp(argv[i], "data:application/x-webkit-test-netscape,returnerrorfromnewstream") == 0)
obj->returnErrorFromNewStream = TRUE;
+ else if (!strcasecmp(argn[i], "src")
+ && !strcasecmp(argv[i], "data:application/x-webkit-test-netscape,alertwhenloaded"))
+ executeScript(obj, "alert('Plugin Loaded!')");
else if (strcasecmp(argn[i], "logfirstsetwindow") == 0)
obj->logSetWindow = TRUE;
else if (strcasecmp(argn[i], "testnpruntime") == 0)
diff --git a/Tools/DumpRenderTree/win/AccessibilityControllerWin.cpp b/Tools/DumpRenderTree/win/AccessibilityControllerWin.cpp
index f03c102..6e4ee46 100644
--- a/Tools/DumpRenderTree/win/AccessibilityControllerWin.cpp
+++ b/Tools/DumpRenderTree/win/AccessibilityControllerWin.cpp
@@ -213,6 +213,10 @@ void AccessibilityController::setLogScrollingStartEvents(bool logScrollingStartE
ASSERT(m_scrollingStartEventHook);
}
+void AccessibilityController::setLogAccessibilityEvents(bool)
+{
+}
+
static string stringEvent(DWORD event)
{
switch(event) {
diff --git a/Tools/DumpRenderTree/win/ImageDiffCommon.vsprops b/Tools/DumpRenderTree/win/ImageDiffCommon.vsprops
index 1156a72..5d41bf4 100644
--- a/Tools/DumpRenderTree/win/ImageDiffCommon.vsprops
+++ b/Tools/DumpRenderTree/win/ImageDiffCommon.vsprops
@@ -7,6 +7,7 @@
<Tool
Name="VCCLCompilerTool"
AdditionalIncludeDirectories="&quot;$(ConfigurationBuildDir)\include&quot;;&quot;$(ConfigurationBuildDir)\include\private&quot;;&quot;$(ConfigurationBuildDir)\include\WebCore\ForwardingHeaders&quot;;&quot;$(WebKitLibrariesDir)\include&quot;;&quot;$(WebKitLibrariesDir)\include\private&quot;"
+ PreprocessorDefinitions="NOMINMAX"
/>
<Tool
Name="VCLinkerTool"
diff --git a/Tools/DumpRenderTree/wx/LayoutTestControllerWx.cpp b/Tools/DumpRenderTree/wx/LayoutTestControllerWx.cpp
index 32b5f7e..1befb77 100644
--- a/Tools/DumpRenderTree/wx/LayoutTestControllerWx.cpp
+++ b/Tools/DumpRenderTree/wx/LayoutTestControllerWx.cpp
@@ -544,3 +544,8 @@ bool LayoutTestController::findString(JSContextRef context, JSStringRef target,
// FIXME: Implement
return false;
}
+
+void LayoutTestController::setSerializeHTTPLoads(bool)
+{
+ // FIXME: Implement.
+}
diff --git a/Tools/GNUmakefile.am b/Tools/GNUmakefile.am
index 3db766f..a208afe 100644
--- a/Tools/GNUmakefile.am
+++ b/Tools/GNUmakefile.am
@@ -69,6 +69,8 @@ Programs_DumpRenderTree_SOURCES = \
Tools/DumpRenderTree/config.h \
Tools/DumpRenderTree/cairo/PixelDumpSupportCairo.cpp \
Tools/DumpRenderTree/cairo/PixelDumpSupportCairo.h \
+ Tools/DumpRenderTree/gtk/AccessibilityCallbacks.h \
+ Tools/DumpRenderTree/gtk/AccessibilityCallbacks.cpp \
Tools/DumpRenderTree/gtk/AccessibilityControllerGtk.cpp \
Tools/DumpRenderTree/gtk/AccessibilityUIElementGtk.cpp \
Tools/DumpRenderTree/gtk/DumpRenderTree.cpp \
@@ -80,6 +82,8 @@ Programs_DumpRenderTree_SOURCES = \
Tools/DumpRenderTree/gtk/GCControllerGtk.cpp \
Tools/DumpRenderTree/gtk/LayoutTestControllerGtk.cpp \
Tools/DumpRenderTree/gtk/PixelDumpSupportGtk.cpp \
+ Tools/DumpRenderTree/gtk/TextInputController.h \
+ Tools/DumpRenderTree/gtk/TextInputController.cpp \
Tools/DumpRenderTree/gtk/WorkQueueItemGtk.cpp \
Source/WebCore/platform/gtk/GtkVersioning.c
diff --git a/Tools/MiniBrowser/DerivedSources.pro b/Tools/MiniBrowser/DerivedSources.pro
index 3ca89ad..8674beb 100644
--- a/Tools/MiniBrowser/DerivedSources.pro
+++ b/Tools/MiniBrowser/DerivedSources.pro
@@ -7,12 +7,13 @@ TARGET = dummy
QMAKE_EXTRA_TARGETS += generated_files
+isEmpty(OUTPUT_DIR): OUTPUT_DIR = ../..
SRC_ROOT_DIR = $$replace(PWD, "/Tools/MiniBrowser", "")
-!exists($$OUTPUT_DIR/Tools/MiniBrowser/qt):system($$QMAKE_MKDIR $$OUTPUT_DIR/Tools/MiniBrowser/qt)
+!exists($$OUTPUT_DIR/MiniBrowser/qt): system($$QMAKE_MKDIR $$OUTPUT_DIR/MiniBrowser/qt)
ualist_copier.input = $$SRC_ROOT_DIR/Tools/QtTestBrowser/useragentlist.txt
-ualist_copier.output = $$OUTPUT_DIR/Tools/MiniBrowser/qt/useragentlist.txt
+ualist_copier.output = $$OUTPUT_DIR/MiniBrowser/qt/useragentlist.txt
ualist_copier.tempNames = $$ualist_copier.input $$ualist_copier.output
ualist_copier.commands = $$QMAKE_COPY $$replace(ualist_copier.tempNames, "/", $$QMAKE_DIR_SEP)
ualist_copier.depends = $$ualist_copier.input
@@ -24,7 +25,7 @@ QMAKE_EXTRA_TARGETS += ualist_copier
# polluting the source tree.
qrc_copier.input = $$SRC_ROOT_DIR/Tools/MiniBrowser/MiniBrowser.qrc
-qrc_copier.output = $$OUTPUT_DIR/Tools/MiniBrowser/qt/MiniBrowser.qrc
+qrc_copier.output = $$OUTPUT_DIR/MiniBrowser/qt/MiniBrowser.qrc
qrc_copier.tempNames = $$qrc_copier.input $$qrc_copier.output
qrc_copier.commands = $$QMAKE_COPY $$replace(qrc_copier.tempNames, "/", $$QMAKE_DIR_SEP)
qrc_copier.depends = ualist_copier $$qrc_copier.input
diff --git a/Tools/MiniBrowser/mac/BrowserWindowController.m b/Tools/MiniBrowser/mac/BrowserWindowController.m
index 3a1ffbd..fd6f2e0 100644
--- a/Tools/MiniBrowser/mac/BrowserWindowController.m
+++ b/Tools/MiniBrowser/mac/BrowserWindowController.m
@@ -351,26 +351,26 @@ static void processDidExit(WKPageRef page, const void *clientInfo)
LOG(@"processDidExit");
}
-static void didChangeBackForwardList(WKPageRef page, const void *clientInfo)
+static void didChangeBackForwardList(WKPageRef page, WKBackForwardListItemRef addedItem, WKArrayRef removedItems, const void *clientInfo)
{
[(BrowserWindowController *)clientInfo validateToolbar];
}
// MARK: Policy Client Callbacks
-static void decidePolicyForNavigationAction(WKPageRef page, WKFrameNavigationType navigationType, WKEventModifiers modifiers, WKEventMouseButton mouseButton, WKURLRef url, WKFrameRef frame, WKFramePolicyListenerRef listener, const void *clientInfo)
+static void decidePolicyForNavigationAction(WKPageRef page, WKFrameRef frame, WKFrameNavigationType navigationType, WKEventModifiers modifiers, WKEventMouseButton mouseButton, WKURLRequestRef request, WKFramePolicyListenerRef listener, WKTypeRef userData, const void* clientInfo)
{
LOG(@"decidePolicyForNavigationAction");
WKFramePolicyListenerUse(listener);
}
-static void decidePolicyForNewWindowAction(WKPageRef page, WKFrameNavigationType navigationType, WKEventModifiers modifiers, WKEventMouseButton mouseButton, WKURLRef url, WKFrameRef frame, WKFramePolicyListenerRef listener, const void *clientInfo)
+static void decidePolicyForNewWindowAction(WKPageRef page, WKFrameRef frame, WKFrameNavigationType navigationType, WKEventModifiers modifiers, WKEventMouseButton mouseButton, WKURLRequestRef request, WKStringRef frameName, WKFramePolicyListenerRef listener, WKTypeRef userData, const void* clientInfo)
{
LOG(@"decidePolicyForNewWindowAction");
WKFramePolicyListenerUse(listener);
}
-static void decidePolicyForMIMEType(WKPageRef page, WKStringRef MIMEType, WKURLRef url, WKFrameRef frame, WKFramePolicyListenerRef listener, const void *clientInfo)
+static void decidePolicyForMIMEType(WKPageRef page, WKFrameRef frame, WKStringRef MIMEType, WKURLRequestRef request, WKFramePolicyListenerRef listener, WKTypeRef userData, const void* clientInfo)
{
WKFramePolicyListenerUse(listener);
}
@@ -645,6 +645,7 @@ static void runOpenPanel(WKPageRef page, WKFrameRef frame, WKOpenPanelParameters
0, // drawFooter
0, // printFrame
0, // showModal
+ 0, // didCompleteRubberBandForMainFrame
};
WKPageSetPageUIClient(_webView.pageRef, &uiClient);
}
diff --git a/Tools/MiniBrowser/mac/WebBundle/WebBundleMain.m b/Tools/MiniBrowser/mac/WebBundle/WebBundleMain.m
index 90db033..fcc6923 100644
--- a/Tools/MiniBrowser/mac/WebBundle/WebBundleMain.m
+++ b/Tools/MiniBrowser/mac/WebBundle/WebBundleMain.m
@@ -64,7 +64,7 @@ void didCreatePage(WKBundleRef bundle, WKBundlePageRef page, const void* clientI
memset(&client, 0, sizeof(client));
client.didClearWindowObjectForFrame = didClearWindowObjectForFrame;
- WKBundlePageSetLoaderClient(page, &client);
+ WKBundlePageSetPageLoaderClient(page, &client);
}
void willDestroyPage(WKBundleRef bundle, WKBundlePageRef page, const void* clientInfo)
diff --git a/Tools/MiniBrowser/qt/BrowserView.cpp b/Tools/MiniBrowser/qt/BrowserView.cpp
index 6118f79..7d6426e 100644
--- a/Tools/MiniBrowser/qt/BrowserView.cpp
+++ b/Tools/MiniBrowser/qt/BrowserView.cpp
@@ -33,17 +33,14 @@
BrowserView::BrowserView(QGraphicsWKView::BackingStoreType backingStoreType, QWKContext* context, QWidget* parent)
: QGraphicsView(parent)
, m_item(0)
- , m_context(context ? context : new QWKContext(this))
{
- m_item = new QGraphicsWKView(m_context, backingStoreType, 0);
+ m_item = new QGraphicsWKView(context, backingStoreType, 0);
setScene(new QGraphicsScene(this));
scene()->addItem(m_item);
setFrameShape(QFrame::NoFrame);
setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
-
- connect(m_item, SIGNAL(titleChanged(QString)), this, SLOT(setWindowTitle(QString)));
}
void BrowserView::resizeEvent(QResizeEvent* event)
diff --git a/Tools/MiniBrowser/qt/BrowserView.h b/Tools/MiniBrowser/qt/BrowserView.h
index e19cc59..593006e 100644
--- a/Tools/MiniBrowser/qt/BrowserView.h
+++ b/Tools/MiniBrowser/qt/BrowserView.h
@@ -48,7 +48,6 @@ protected:
private:
QGraphicsWKView* m_item;
- QWKContext* m_context;
};
#endif
diff --git a/Tools/MiniBrowser/qt/BrowserWindow.cpp b/Tools/MiniBrowser/qt/BrowserWindow.cpp
index c63c9d6..0405e9e 100644
--- a/Tools/MiniBrowser/qt/BrowserWindow.cpp
+++ b/Tools/MiniBrowser/qt/BrowserWindow.cpp
@@ -28,34 +28,92 @@
#include "BrowserWindow.h"
+#include "qwkpreferences.h"
+
static QWKPage* newPageFunction(QWKPage* page)
{
BrowserWindow* window = new BrowserWindow(page->context());
return window->page();
}
-QGraphicsWKView::BackingStoreType BrowserWindow::backingStoreTypeForNewWindow = QGraphicsWKView::Simple;
+QVector<qreal> BrowserWindow::m_zoomLevels;
-BrowserWindow::BrowserWindow(QWKContext* context)
+BrowserWindow::BrowserWindow(QWKContext* context, WindowOptions* options)
+ : m_isZoomTextOnly(false)
+ , m_currentZoom(1)
+ , m_context(context)
{
- setAttribute(Qt::WA_DeleteOnClose);
+ if (options)
+ m_windowOptions = *options;
+ else {
+ WindowOptions tmpOptions;
+ m_windowOptions = tmpOptions;
+ }
- m_menu = new QMenuBar();
- m_browser = new BrowserView(backingStoreTypeForNewWindow, context);
- m_addressBar = new QLineEdit();
+ if (m_windowOptions.useTiledBackingStore)
+ m_browser = new BrowserView(QGraphicsWKView::Tiled, context);
+ else
+ m_browser = new BrowserView(QGraphicsWKView::Simple, context);
- m_menu->addAction("New Window", this, SLOT(newWindow()));
- m_menu->addAction("Change User Agent", this, SLOT(showUserAgentDialog()));
+ setAttribute(Qt::WA_DeleteOnClose);
- m_menu->addSeparator();
- m_menu->addAction("Quit", this, SLOT(close()));
+ connect(m_browser->view(), SIGNAL(loadProgress(int)), SLOT(loadProgress(int)));
+ connect(m_browser->view(), SIGNAL(titleChanged(const QString&)), SLOT(setWindowTitle(const QString&)));
+ connect(m_browser->view(), SIGNAL(urlChanged(const QUrl&)), SLOT(urlChanged(const QUrl&)));
+ this->setCentralWidget(m_browser);
m_browser->setFocus(Qt::OtherFocusReason);
+ QMenu* fileMenu = menuBar()->addMenu("&File");
+ fileMenu->addAction("New Window", this, SLOT(newWindow()), QKeySequence::New);
+ fileMenu->addAction("Open File", this, SLOT(openFile()), QKeySequence::Open);
+ fileMenu->addSeparator();
+ fileMenu->addAction("Quit", this, SLOT(close()));
+
+ QMenu* viewMenu = menuBar()->addMenu("&View");
+ viewMenu->addAction(page()->action(QWKPage::Stop));
+ viewMenu->addAction(page()->action(QWKPage::Reload));
+ viewMenu->addSeparator();
+ QAction* zoomIn = viewMenu->addAction("Zoom &In", this, SLOT(zoomIn()));
+ QAction* zoomOut = viewMenu->addAction("Zoom &Out", this, SLOT(zoomOut()));
+ QAction* resetZoom = viewMenu->addAction("Reset Zoom", this, SLOT(resetZoom()));
+ QAction* zoomText = viewMenu->addAction("Zoom Text Only", this, SLOT(toggleZoomTextOnly(bool)));
+ zoomText->setCheckable(true);
+ zoomText->setChecked(false);
+ viewMenu->addSeparator();
+ viewMenu->addAction("Take Screen Shot...", this, SLOT(screenshot()));
+
+ zoomIn->setShortcut(QKeySequence(Qt::CTRL | Qt::Key_Plus));
+ zoomOut->setShortcut(QKeySequence(Qt::CTRL | Qt::Key_Minus));
+ resetZoom->setShortcut(QKeySequence(Qt::CTRL | Qt::Key_0));
+
+ QMenu* windowMenu = menuBar()->addMenu("&Window");
+ QAction* toggleFullScreen = windowMenu->addAction("Toggle FullScreen", this, SIGNAL(enteredFullScreenMode(bool)));
+ toggleFullScreen->setShortcut(Qt::Key_F11);
+ toggleFullScreen->setCheckable(true);
+ toggleFullScreen->setChecked(false);
+ // When exit fullscreen mode by clicking on the exit area (bottom right corner) we must
+ // uncheck the Toggle FullScreen action.
+ toggleFullScreen->connect(this, SIGNAL(enteredFullScreenMode(bool)), SLOT(setChecked(bool)));
+ connect(this, SIGNAL(enteredFullScreenMode(bool)), this, SLOT(toggleFullScreenMode(bool)));
+
+ QMenu* toolsMenu = menuBar()->addMenu("&Develop");
+ QAction* toggleFrameFlattening = toolsMenu->addAction("Toggle Frame Flattening", this, SLOT(toggleFrameFlattening(bool)));
+ toggleFrameFlattening->setCheckable(true);
+ toggleFrameFlattening->setChecked(false);
+ toolsMenu->addSeparator();
+ toolsMenu->addAction("Change User Agent", this, SLOT(showUserAgentDialog()));
+
+ QMenu* settingsMenu = menuBar()->addMenu("&Settings");
+ QAction* toggleAutoLoadImages = settingsMenu->addAction("Disable Auto Load Images", this, SLOT(toggleAutoLoadImages(bool)));
+ toggleAutoLoadImages->setCheckable(true);
+ toggleAutoLoadImages->setChecked(false);
+ QAction* toggleDisableJavaScript = settingsMenu->addAction("Disable JavaScript", this, SLOT(toggleDisableJavaScript(bool)));
+ toggleDisableJavaScript->setCheckable(true);
+ toggleDisableJavaScript->setChecked(false);
+
+ m_addressBar = new QLineEdit();
connect(m_addressBar, SIGNAL(returnPressed()), SLOT(changeLocation()));
- connect(m_browser->view(), SIGNAL(loadProgress(int)), SLOT(loadProgress(int)));
- connect(m_browser->view(), SIGNAL(titleChanged(const QString&)), SLOT(titleChanged(const QString&)));
- connect(m_browser->view(), SIGNAL(urlChanged(const QUrl&)), SLOT(urlChanged(const QUrl&)));
QToolBar* bar = addToolBar("Navigation");
bar->addAction(page()->action(QWKPage::Back));
@@ -64,17 +122,19 @@ BrowserWindow::BrowserWindow(QWKContext* context)
bar->addAction(page()->action(QWKPage::Stop));
bar->addWidget(m_addressBar);
- this->setMenuBar(m_menu);
- this->setCentralWidget(m_browser);
-
- m_browser->setFocus(Qt::OtherFocusReason);
-
QShortcut* selectAddressBar = new QShortcut(Qt::CTRL | Qt::Key_L, this);
connect(selectAddressBar, SIGNAL(activated()), this, SLOT(openLocation()));
page()->setCreateNewPageFunction(newPageFunction);
- resize(960, 640);
+ // the zoom values are chosen to be like in Mozilla Firefox 3
+ if (!m_zoomLevels.count()) {
+ m_zoomLevels << 0.3 << 0.5 << 0.67 << 0.8 << 0.9;
+ m_zoomLevels << 1;
+ m_zoomLevels << 1.1 << 1.2 << 1.33 << 1.5 << 1.7 << 2 << 2.4 << 3;
+ }
+
+ resize(800, 600);
show();
}
@@ -91,7 +151,14 @@ QWKPage* BrowserWindow::page()
BrowserWindow* BrowserWindow::newWindow(const QString& url)
{
- BrowserWindow* window = new BrowserWindow;
+ BrowserWindow* window;
+ if (m_windowOptions.useSeparateWebProcessPerWindow) {
+ QWKContext* context = new QWKContext();
+ window = new BrowserWindow(context);
+ context->setParent(window);
+ } else
+ window = new BrowserWindow(m_context);
+
window->load(url);
return window;
}
@@ -127,35 +194,113 @@ void BrowserWindow::loadProgress(int progress)
m_addressBar->setPalette(pallete);
}
-void BrowserWindow::titleChanged(const QString& title)
-{
- setWindowTitle(title);
-}
-
void BrowserWindow::urlChanged(const QUrl& url)
{
m_addressBar->setText(url.toString());
}
-void BrowserWindow::updateUserAgentList()
+void BrowserWindow::openFile()
{
- QFile file(":/useragentlist.txt");
+#ifndef QT_NO_FILEDIALOG
+ static const QString filter("HTML Files (*.htm *.html *.xhtml);;Text Files (*.txt);;Image Files (*.gif *.jpg *.png);;SVG Files (*.svg);;All Files (*)");
+
+ QFileDialog fileDialog(this, tr("Open"), QString(), filter);
+ fileDialog.setAcceptMode(QFileDialog::AcceptOpen);
+ fileDialog.setFileMode(QFileDialog::ExistingFile);
+ fileDialog.setOptions(QFileDialog::ReadOnly);
+
+ if (fileDialog.exec()) {
+ QString selectedFile = fileDialog.selectedFiles()[0];
+ if (!selectedFile.isEmpty())
+ load(selectedFile);
+ }
+#endif
+}
- if (file.open(QIODevice::ReadOnly)) {
- while (!file.atEnd()) {
- QString agent = file.readLine().trimmed();
- if (!m_userAgentList.contains(agent))
- m_userAgentList << agent;
- }
- file.close();
+void BrowserWindow::screenshot()
+{
+ QPixmap pixmap = QPixmap::grabWidget(m_browser);
+ QLabel* label = 0;
+#if !defined(Q_OS_SYMBIAN)
+ label = new QLabel;
+ label->setAttribute(Qt::WA_DeleteOnClose);
+ label->setWindowTitle("Screenshot - Preview");
+ label->setPixmap(pixmap);
+ label->show();
+#endif
+
+#ifndef QT_NO_FILEDIALOG
+ QString fileName = QFileDialog::getSaveFileName(label, "Screenshot", QString(), QString("PNG File (.png)"));
+ if (!fileName.isEmpty()) {
+ QRegExp rx("*.png");
+ rx.setCaseSensitivity(Qt::CaseInsensitive);
+ rx.setPatternSyntax(QRegExp::Wildcard);
+
+ if (!rx.exactMatch(fileName))
+ fileName += ".png";
+
+ pixmap.save(fileName, "png");
+ if (label)
+ label->setWindowTitle(QString("Screenshot - Saved at %1").arg(fileName));
}
+#endif
+}
- Q_ASSERT(!m_userAgentList.isEmpty());
- QWKPage* wkPage = page();
- if (!(wkPage->customUserAgent().isEmpty() || m_userAgentList.contains(wkPage->customUserAgent())))
- m_userAgentList << wkPage->customUserAgent();
+void BrowserWindow::zoomIn()
+{
+ if (m_isZoomTextOnly)
+ m_currentZoom = page()->textZoomFactor();
+ else
+ m_currentZoom = page()->pageZoomFactor();
+
+ int i = m_zoomLevels.indexOf(m_currentZoom);
+ Q_ASSERT(i >= 0);
+ if (i < m_zoomLevels.count() - 1)
+ m_currentZoom = m_zoomLevels[i + 1];
+
+ applyZoom();
}
+void BrowserWindow::zoomOut()
+{
+ if (m_isZoomTextOnly)
+ m_currentZoom = page()->textZoomFactor();
+ else
+ m_currentZoom = page()->pageZoomFactor();
+
+ int i = m_zoomLevels.indexOf(m_currentZoom);
+ Q_ASSERT(i >= 0);
+ if (i > 0)
+ m_currentZoom = m_zoomLevels[i - 1];
+
+ applyZoom();
+}
+
+void BrowserWindow::resetZoom()
+{
+ m_currentZoom = 1;
+ applyZoom();
+}
+
+void BrowserWindow::toggleZoomTextOnly(bool b)
+{
+ m_isZoomTextOnly = b;
+}
+
+void BrowserWindow::toggleFullScreenMode(bool enable)
+{
+ if (enable)
+ setWindowState(Qt::WindowFullScreen);
+ else
+ setWindowState(Qt::WindowNoState);
+}
+
+void BrowserWindow::toggleFrameFlattening(bool toggle)
+{
+ page()->preferences()->setAttribute(QWKPreferences::FrameFlatteningEnabled, toggle);
+}
+
+
void BrowserWindow::showUserAgentDialog()
{
updateUserAgentList();
@@ -185,9 +330,45 @@ void BrowserWindow::showUserAgentDialog()
page()->setCustomUserAgent(combo->currentText());
}
+void BrowserWindow::toggleDisableJavaScript(bool enable)
+{
+ page()->preferences()->setAttribute(QWKPreferences::JavascriptEnabled, !enable);
+}
+
+void BrowserWindow::toggleAutoLoadImages(bool enable)
+{
+ page()->preferences()->setAttribute(QWKPreferences::AutoLoadImages, !enable);
+}
+
+void BrowserWindow::updateUserAgentList()
+{
+ QFile file(":/useragentlist.txt");
+
+ if (file.open(QIODevice::ReadOnly)) {
+ while (!file.atEnd()) {
+ QString agent = file.readLine().trimmed();
+ if (!m_userAgentList.contains(agent))
+ m_userAgentList << agent;
+ }
+ file.close();
+ }
+
+ Q_ASSERT(!m_userAgentList.isEmpty());
+ QWKPage* wkPage = page();
+ if (!(wkPage->customUserAgent().isEmpty() || m_userAgentList.contains(wkPage->customUserAgent())))
+ m_userAgentList << wkPage->customUserAgent();
+}
+
+void BrowserWindow::applyZoom()
+{
+ if (m_isZoomTextOnly)
+ page()->setTextZoomFactor(m_currentZoom);
+ else
+ page()->setPageZoomFactor(m_currentZoom);
+}
+
BrowserWindow::~BrowserWindow()
{
delete m_addressBar;
delete m_browser;
- delete m_menu;
}
diff --git a/Tools/MiniBrowser/qt/BrowserWindow.h b/Tools/MiniBrowser/qt/BrowserWindow.h
index f984309..c79b2d0 100644
--- a/Tools/MiniBrowser/qt/BrowserWindow.h
+++ b/Tools/MiniBrowser/qt/BrowserWindow.h
@@ -30,38 +30,60 @@
#define BrowserWindow_h
#include "BrowserView.h"
+
+#include "MiniBrowserApplication.h"
#include <QStringList>
#include <QtGui>
-#include <qgraphicswkview.h>
class BrowserWindow : public QMainWindow {
Q_OBJECT
public:
- BrowserWindow(QWKContext* = 0);
+ BrowserWindow(QWKContext*, WindowOptions* = 0);
~BrowserWindow();
void load(const QString& url);
QWKPage* page();
- static QGraphicsWKView::BackingStoreType backingStoreTypeForNewWindow;
-
public slots:
BrowserWindow* newWindow(const QString& url = "about:blank");
void openLocation();
+signals:
+ void enteredFullScreenMode(bool on);
+
protected slots:
void changeLocation();
void loadProgress(int progress);
- void titleChanged(const QString&);
void urlChanged(const QUrl&);
+ void openFile();
+
+ void zoomIn();
+ void zoomOut();
+ void resetZoom();
+ void toggleZoomTextOnly(bool on);
+ void screenshot();
+
+ void toggleFullScreenMode(bool enable);
+
+ void toggleFrameFlattening(bool);
void showUserAgentDialog();
+ void toggleAutoLoadImages(bool);
+ void toggleDisableJavaScript(bool);
+
private:
void updateUserAgentList();
+ void applyZoom();
+
+ static QVector<qreal> m_zoomLevels;
+ bool m_isZoomTextOnly;
+ qreal m_currentZoom;
+
+ QWKContext* m_context;
+ WindowOptions m_windowOptions;
BrowserView* m_browser;
- QMenuBar* m_menu;
QLineEdit* m_addressBar;
QStringList m_userAgentList;
};
diff --git a/Tools/MiniBrowser/qt/MiniBrowser.pro b/Tools/MiniBrowser/qt/MiniBrowser.pro
index c297207..cefa678 100644
--- a/Tools/MiniBrowser/qt/MiniBrowser.pro
+++ b/Tools/MiniBrowser/qt/MiniBrowser.pro
@@ -2,18 +2,22 @@ TEMPLATE = app
TARGET = MiniBrowser
SOURCES += \
- main.cpp \
BrowserView.cpp \
BrowserWindow.cpp \
+ main.cpp \
+ MiniBrowserApplication.cpp \
+ UrlLoader.cpp \
+ utils.cpp \
HEADERS += \
BrowserView.h \
BrowserWindow.h \
-
-CONFIG += uitools
+ MiniBrowserApplication.h \
+ UrlLoader.h \
+ utils.h \
isEmpty(OUTPUT_DIR): OUTPUT_DIR = ../../..
-include(../../../WebKit.pri)
+include(../../../Source/WebKit.pri)
INCLUDEPATH += \
$$PWD/../../../Source/WebKit2/ \
@@ -55,4 +59,4 @@ contains(QT_CONFIG, opengl) {
# We copy the resource file to the build directory.
# The copier is defined in Tools/MiniBrowser/DerivedSources.pro.
RESOURCES += \
- $$OUTPUT_DIR/Tools/MiniBrowser/qt/MiniBrowser.qrc
+ $$OUTPUT_DIR/MiniBrowser/qt/MiniBrowser.qrc
diff --git a/Tools/MiniBrowser/qt/MiniBrowserApplication.cpp b/Tools/MiniBrowser/qt/MiniBrowserApplication.cpp
new file mode 100644
index 0000000..4ed7895
--- /dev/null
+++ b/Tools/MiniBrowser/qt/MiniBrowserApplication.cpp
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies)
+ * Copyright (C) 2010 University of Szeged
+ *
+ * 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 COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "MiniBrowserApplication.h"
+
+#include "utils.h"
+#include <QRegExp>
+
+MiniBrowserApplication::MiniBrowserApplication(int& argc, char** argv)
+ : QApplication(argc, argv, QApplication::GuiServer)
+ , m_windowOptions()
+ , m_isRobotized(false)
+ , m_robotTimeoutSeconds(0)
+ , m_robotExtraTimeSeconds(0)
+{
+ setOrganizationName("Nokia");
+ setApplicationName("QtMiniBrowser");
+ setApplicationVersion("0.1");
+
+ handleUserOptions();
+}
+
+void MiniBrowserApplication::handleUserOptions()
+{
+ QStringList args = arguments();
+ QFileInfo program(args.at(0));
+ QString programName("MiniBrowser");
+ if (program.exists())
+ programName = program.baseName();
+
+ if (args.contains("-help")) {
+ qDebug() << "Usage:" << programName.toLatin1().data()
+ << "[-r list]"
+ << "[-robot-timeout seconds]"
+ << "[-robot-extra-time seconds]"
+ << "[-tiled-backing-store]"
+ << "[-separate-web-process-per-window]"
+ << "URLs";
+ appQuit(0);
+ }
+
+ int robotIndex = args.indexOf("-r");
+ if (robotIndex != -1) {
+ QString listFile = takeOptionValue(&args, robotIndex);
+ if (listFile.isEmpty())
+ appQuit(1, "-r needs a list file to start in robotized mode");
+ if (!QFile::exists(listFile))
+ appQuit(1, "The list file supplied to -r does not exist.");
+
+ m_isRobotized = true;
+ m_urls = QStringList(listFile);
+ } else {
+ int lastArg = args.lastIndexOf(QRegExp("^-.*"));
+ m_urls = (lastArg != -1) ? args.mid(++lastArg) : args.mid(1);
+ }
+
+ int robotTimeoutIndex = args.indexOf("-robot-timeout");
+ if (robotTimeoutIndex != -1)
+ m_robotTimeoutSeconds = takeOptionValue(&args, robotTimeoutIndex).toInt();
+
+ int robotExtraTimeIndex = args.indexOf("-robot-extra-time");
+ if (robotExtraTimeIndex != -1)
+ m_robotExtraTimeSeconds = takeOptionValue(&args, robotExtraTimeIndex).toInt();
+
+ if (args.contains("-tiled-backing-store"))
+ m_windowOptions.useTiledBackingStore = true;
+
+ if (args.contains("-separate-web-process-per-window"))
+ m_windowOptions.useSeparateWebProcessPerWindow = true;
+}
diff --git a/Tools/MiniBrowser/qt/MiniBrowserApplication.h b/Tools/MiniBrowser/qt/MiniBrowserApplication.h
new file mode 100644
index 0000000..2039764
--- /dev/null
+++ b/Tools/MiniBrowser/qt/MiniBrowserApplication.h
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies)
+ * Copyright (C) 2010 University of Szeged
+ *
+ * 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 COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef MiniBrowserApplication_h
+#define MiniBrowserApplication_h
+
+#include <QStringList>
+#include <QtGui>
+
+struct WindowOptions {
+ WindowOptions()
+ : useTiledBackingStore(false)
+ , useSeparateWebProcessPerWindow(false)
+ {
+ }
+
+ bool useTiledBackingStore;
+ bool useSeparateWebProcessPerWindow;
+};
+
+class MiniBrowserApplication : public QApplication {
+ Q_OBJECT
+
+public:
+ MiniBrowserApplication(int& argc, char** argv);
+ QStringList urls() const { return m_urls; }
+ bool isRobotized() const { return m_isRobotized; }
+ int robotTimeout() const { return m_robotTimeoutSeconds; }
+ int robotExtraTime() const { return m_robotExtraTimeSeconds; }
+
+ WindowOptions m_windowOptions;
+
+private:
+ void handleUserOptions();
+
+private:
+ bool m_isRobotized;
+ int m_robotTimeoutSeconds;
+ int m_robotExtraTimeSeconds;
+ QStringList m_urls;
+};
+
+#endif
diff --git a/Tools/MiniBrowser/qt/UrlLoader.cpp b/Tools/MiniBrowser/qt/UrlLoader.cpp
new file mode 100644
index 0000000..600d477
--- /dev/null
+++ b/Tools/MiniBrowser/qt/UrlLoader.cpp
@@ -0,0 +1,129 @@
+/*
+ * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies)
+ * Copyright (C) 2009 University of Szeged
+ *
+ * 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 COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "UrlLoader.h"
+
+#include <QDebug>
+#include <QFile>
+
+UrlLoader::UrlLoader(BrowserWindow* browserWindow, const QString& inputFileName, int timeoutSeconds, int extraTimeSeconds)
+ : m_browserWindow(browserWindow)
+ , m_stdOut(stdout)
+ , m_loaded(0)
+ , m_numFramesLoading(0)
+{
+ m_checkIfFinishedTimer.setInterval(200);
+ m_checkIfFinishedTimer.setSingleShot(true);
+ connect(&m_checkIfFinishedTimer, SIGNAL(timeout()), this, SLOT(checkIfFinished()));
+ // loadStarted and loadFinished on QWebPage is emitted for each frame/sub-frame
+ connect(m_browserWindow->page(), SIGNAL(loadStarted()), this, SLOT(frameLoadStarted()));
+ connect(m_browserWindow->page(), SIGNAL(loadFinished(bool)), this, SLOT(frameLoadFinished()));
+
+ if (timeoutSeconds) {
+ m_timeoutTimer.setInterval(timeoutSeconds * 1000);
+ m_timeoutTimer.setSingleShot(true);
+ connect(m_browserWindow, SIGNAL(loadStarted()), &m_timeoutTimer, SLOT(start()));
+ connect(&m_timeoutTimer, SIGNAL(timeout()), this, SLOT(loadNext()));
+ }
+ if (extraTimeSeconds) {
+ m_extraTimeTimer.setInterval(extraTimeSeconds * 1000);
+ m_extraTimeTimer.setSingleShot(true);
+ connect(this, SIGNAL(pageLoadFinished()), &m_extraTimeTimer, SLOT(start()));
+ connect(&m_extraTimeTimer, SIGNAL(timeout()), this, SLOT(loadNext()));
+ } else
+ connect(this, SIGNAL(pageLoadFinished()), this, SLOT(loadNext()));
+ loadUrlList(inputFileName);
+}
+
+void UrlLoader::loadNext()
+{
+ m_timeoutTimer.stop();
+ m_extraTimeTimer.stop();
+ m_checkIfFinishedTimer.stop();
+ m_numFramesLoading = 0;
+ QString qstr;
+ if (getUrl(qstr)) {
+ QUrl url(qstr, QUrl::StrictMode);
+ if (url.isValid()) {
+ m_stdOut << "Loading " << qstr << " ......" << ++m_loaded << endl;
+ m_browserWindow->load(url.toString());
+ } else
+ loadNext();
+ } else
+ disconnect(m_browserWindow, 0, this, 0);
+}
+
+void UrlLoader::checkIfFinished()
+{
+ if (!m_numFramesLoading)
+ emit pageLoadFinished();
+}
+
+void UrlLoader::frameLoadStarted()
+{
+ ++m_numFramesLoading;
+ m_checkIfFinishedTimer.stop();
+}
+
+void UrlLoader::frameLoadFinished()
+{
+ Q_ASSERT(m_numFramesLoading > 0);
+ --m_numFramesLoading;
+ // Once our frame has finished loading, wait a moment to call loadNext for cases
+ // where a sub-frame starts loading or another frame is loaded through JavaScript.
+ m_checkIfFinishedTimer.start();
+}
+
+void UrlLoader::loadUrlList(const QString& inputFileName)
+{
+ QFile inputFile(inputFileName);
+ if (inputFile.open(QIODevice::ReadOnly | QIODevice::Text)) {
+ QTextStream stream(&inputFile);
+ QString line;
+ while (true) {
+ line = stream.readLine();
+ if (line.isNull())
+ break;
+ m_urls.append(line);
+ }
+ } else {
+ qDebug() << "Can't open list file";
+ exit(0);
+ }
+ m_index = 0;
+ inputFile.close();
+}
+
+bool UrlLoader::getUrl(QString& qstr)
+{
+ if (m_index == m_urls.size())
+ return false;
+
+ qstr = m_urls[m_index++];
+ return true;
+}
diff --git a/Tools/MiniBrowser/qt/UrlLoader.h b/Tools/MiniBrowser/qt/UrlLoader.h
new file mode 100644
index 0000000..01e67c3
--- /dev/null
+++ b/Tools/MiniBrowser/qt/UrlLoader.h
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies)
+ * Copyright (C) 2009 University of Szeged
+ *
+ * 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 COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef UrlLoader_h
+#define UrlLoader_h
+
+#include "BrowserWindow.h"
+
+#include <QTextStream>
+#include <QTimer>
+#include <QVector>
+
+class UrlLoader : public QObject {
+ Q_OBJECT
+
+public:
+ UrlLoader(BrowserWindow*, const QString&, int, int);
+
+public slots:
+ void loadNext();
+
+private slots:
+ void checkIfFinished();
+ void frameLoadStarted();
+ void frameLoadFinished();
+
+signals:
+ void pageLoadFinished();
+
+private:
+ void loadUrlList(const QString& inputFileName);
+ bool getUrl(QString& qstr);
+
+private:
+ QVector<QString> m_urls;
+ int m_index;
+ BrowserWindow* m_browserWindow;
+ QTextStream m_stdOut;
+ int m_loaded;
+ QTimer m_timeoutTimer;
+ QTimer m_extraTimeTimer;
+ QTimer m_checkIfFinishedTimer;
+ int m_numFramesLoading;
+};
+
+#endif
diff --git a/Tools/MiniBrowser/qt/main.cpp b/Tools/MiniBrowser/qt/main.cpp
index 8c987c5..8f4c1ea 100644
--- a/Tools/MiniBrowser/qt/main.cpp
+++ b/Tools/MiniBrowser/qt/main.cpp
@@ -27,38 +27,46 @@
*/
#include "BrowserWindow.h"
+
+#include "MiniBrowserApplication.h"
+#include "UrlLoader.h"
#include <QLatin1String>
#include <QRegExp>
#include <qgraphicswkview.h>
#include <QtGui>
-int main(int argc, char** argv) {
- QApplication app(argc, argv);
-
- QStringList args = QApplication::arguments();
- args.removeAt(0);
+int main(int argc, char** argv)
+{
+ MiniBrowserApplication app(argc, argv);
- QGraphicsWKView::BackingStoreType backingStoreTypeToUse = QGraphicsWKView::Simple;
- int indexOfTiledOption;
- if ((indexOfTiledOption = args.indexOf(QRegExp(QLatin1String("-tiled")))) != -1) {
- backingStoreTypeToUse = QGraphicsWKView::Tiled;
- args.removeAt(indexOfTiledOption);
+ if (app.isRobotized()) {
+ QWKContext* context = new QWKContext;
+ BrowserWindow* window = new BrowserWindow(context, &app.m_windowOptions);
+ UrlLoader loader(window, app.urls().at(0), app.robotTimeout(), app.robotExtraTime());
+ loader.loadNext();
+ window->show();
+ return app.exec();
}
- if (args.isEmpty()) {
+ QStringList urls = app.urls();
+
+ if (urls.isEmpty()) {
QString defaultUrl = QString("file://%1/%2").arg(QDir::homePath()).arg(QLatin1String("index.html"));
if (QDir(defaultUrl).exists())
- args.append(defaultUrl);
+ urls.append(defaultUrl);
else
- args.append("http://www.google.com");
+ urls.append("http://www.google.com");
}
- BrowserWindow::backingStoreTypeForNewWindow = backingStoreTypeToUse;
- BrowserWindow* window = new BrowserWindow;
- window->load(args[0]);
+ QWKContext* context = new QWKContext;
+ BrowserWindow* window = new BrowserWindow(context, &app.m_windowOptions);
+ if (app.m_windowOptions.useSeparateWebProcessPerWindow)
+ context->setParent(window);
+
+ window->load(urls.at(0));
- for (int i = 1; i < args.size(); ++i)
- window->newWindow(args[i]);
+ for (int i = 1; i < urls.size(); ++i)
+ window->newWindow(urls.at(i));
app.exec();
diff --git a/Tools/MiniBrowser/qt/utils.cpp b/Tools/MiniBrowser/qt/utils.cpp
new file mode 100644
index 0000000..494da71
--- /dev/null
+++ b/Tools/MiniBrowser/qt/utils.cpp
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies)
+ * Copyright (C) 2011 University of Szeged
+ *
+ * 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 COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "utils.h"
+
+QString takeOptionValue(QStringList* arguments, int index)
+{
+ QString result;
+
+ if (++index < arguments->count() && !arguments->at(index).startsWith("-"))
+ result = arguments->takeAt(index);
+
+ return result;
+}
+
+QString formatKeys(QList<QString> keys)
+{
+ QString result;
+ for (int i = 0; i < keys.count() - 1; i++)
+ result.append(keys.at(i) + "|");
+ result.append(keys.last());
+ return result;
+}
+
+QList<QString> enumToKeys(const QMetaObject o, const QString& name, const QString& strip)
+{
+ QList<QString> list;
+
+ int enumIndex = o.indexOfEnumerator(name.toLatin1().data());
+ QMetaEnum enumerator = o.enumerator(enumIndex);
+
+ if (enumerator.isValid()) {
+ for (int i = 0; i < enumerator.keyCount(); i++) {
+ QString key(enumerator.valueToKey(i));
+ list.append(key.remove(strip));
+ }
+ }
+
+ return list;
+}
+
+void appQuit(int exitCode, const QString& msg)
+{
+ if (!msg.isEmpty()) {
+ if (exitCode > 0)
+ qDebug("ERROR: %s", msg.toLatin1().data());
+ else
+ qDebug() << msg;
+ }
+ exit(exitCode);
+}
+
+QUrl urlFromUserInput(const QString& string)
+{
+ QString input(string);
+ QFileInfo fi(input);
+ if (fi.exists() && fi.isRelative())
+ input = fi.absoluteFilePath();
+
+ return QUrl::fromUserInput(input);
+}
diff --git a/Tools/MiniBrowser/qt/utils.h b/Tools/MiniBrowser/qt/utils.h
new file mode 100644
index 0000000..2ec7af2
--- /dev/null
+++ b/Tools/MiniBrowser/qt/utils.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies)
+ * Copyright (C) 2011 University of Szeged
+ *
+ * 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 COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef utils_h
+#define utils_h
+
+#include <QtCore>
+
+#ifndef NO_RETURN
+#if defined(__CC_ARM) || defined(__ARMCC__)
+#define NO_RETURN __declspec(noreturn)
+#elif defined(__GNUC__)
+#define NO_RETURN __attribute((__noreturn__))
+#else
+#define NO_RETURN
+#endif
+#endif
+
+// options handling
+QString takeOptionValue(QStringList* arguments, int index);
+QString formatKeys(QList<QString> keys);
+QList<QString> enumToKeys(const QMetaObject, const QString&, const QString&);
+
+NO_RETURN void appQuit(int status, const QString& msg = QString());
+
+QUrl urlFromUserInput(const QString& input);
+
+#endif
diff --git a/Tools/QtTestBrowser/QtTestBrowser.pro b/Tools/QtTestBrowser/QtTestBrowser.pro
index 62d2c02..6c8cdf4 100644
--- a/Tools/QtTestBrowser/QtTestBrowser.pro
+++ b/Tools/QtTestBrowser/QtTestBrowser.pro
@@ -25,7 +25,7 @@ HEADERS += \
CONFIG += uitools
isEmpty(OUTPUT_DIR): OUTPUT_DIR = ../..
-include(../../WebKit.pri)
+include(../../Source/WebKit.pri)
DESTDIR = $$OUTPUT_DIR/bin
!CONFIG(standalone_package): CONFIG -= app_bundle
diff --git a/Tools/QtTestBrowser/launcherwindow.cpp b/Tools/QtTestBrowser/launcherwindow.cpp
index 067b146..bd332fc 100644
--- a/Tools/QtTestBrowser/launcherwindow.cpp
+++ b/Tools/QtTestBrowser/launcherwindow.cpp
@@ -96,6 +96,7 @@ void LauncherWindow::initializeView()
{
delete m_view;
+ m_inputUrl = addressUrl();
QUrl url = page()->mainFrame()->url();
setPage(new WebPage(this));
page()->setQnamThreaded(m_windowOptions.useThreadedQnam);
@@ -142,6 +143,10 @@ void LauncherWindow::initializeView()
if (url.isValid())
page()->mainFrame()->load(url);
+ else {
+ setAddressUrl(m_inputUrl);
+ m_inputUrl = QString();
+ }
}
void LauncherWindow::applyPrefs()
@@ -259,6 +264,24 @@ void LauncherWindow::createChrome()
toolsMenu->addSeparator();
+ QAction* toggleLocalStorage = toolsMenu->addAction("Enable Local Storage", this, SLOT(toggleLocalStorage(bool)));
+ toggleLocalStorage->setCheckable(true);
+ toggleLocalStorage->setChecked(m_windowOptions.useLocalStorage);
+
+ QAction* toggleOfflineStorageDatabase = toolsMenu->addAction("Enable Offline Storage Database", this, SLOT(toggleOfflineStorageDatabase(bool)));
+ toggleOfflineStorageDatabase->setCheckable(true);
+ toggleOfflineStorageDatabase->setChecked(m_windowOptions.useOfflineStorageDatabase);
+
+ QAction* toggleOfflineWebApplicationCache = toolsMenu->addAction("Enable Offline Web Application Cache", this, SLOT(toggleOfflineWebApplicationCache(bool)));
+ toggleOfflineWebApplicationCache->setCheckable(true);
+ toggleOfflineWebApplicationCache->setChecked(m_windowOptions.useOfflineWebApplicationCache);
+
+ QAction* offlineStorageDefaultQuotaAction = toolsMenu->addAction("Set Offline Storage Default Quota Size", this, SLOT(setOfflineStorageDefaultQuota()));
+ offlineStorageDefaultQuotaAction->setCheckable(true);
+ offlineStorageDefaultQuotaAction->setChecked(m_windowOptions.offlineStorageDefaultQuotaSize);
+
+ toolsMenu->addSeparator();
+
QAction* userAgentAction = toolsMenu->addAction("Change User Agent", this, SLOT(showUserAgentDialog()));
userAgentAction->setShortcut(QKeySequence(Qt::CTRL | Qt::SHIFT | Qt::Key_U));
@@ -367,6 +390,14 @@ void LauncherWindow::createChrome()
QMenu* settingsMenu = menuBar()->addMenu("&Settings");
+ QAction* toggleAutoLoadImages = settingsMenu->addAction("Disable Auto Load Images", this, SLOT(toggleAutoLoadImages(bool)));
+ toggleAutoLoadImages->setCheckable(true);
+ toggleAutoLoadImages->setChecked(false);
+
+ QAction* togglePlugins = settingsMenu->addAction("Disable Plugins", this, SLOT(togglePlugins(bool)));
+ togglePlugins->setCheckable(true);
+ togglePlugins->setChecked(false);
+
QAction* toggleInterruptingJavaScripteEnabled = settingsMenu->addAction("Enable interrupting js scripts", this, SLOT(toggleInterruptingJavaScriptEnabled(bool)));
toggleInterruptingJavaScripteEnabled->setCheckable(true);
toggleInterruptingJavaScripteEnabled->setChecked(false);
@@ -530,8 +561,13 @@ void LauncherWindow::loadStarted()
void LauncherWindow::loadFinished()
{
QUrl url = page()->mainFrame()->url();
- setAddressUrl(url.toString(QUrl::RemoveUserInfo));
addCompleterEntry(url);
+ if (m_inputUrl.isEmpty())
+ setAddressUrl(url.toString(QUrl::RemoveUserInfo));
+ else {
+ setAddressUrl(m_inputUrl);
+ m_inputUrl = QString();
+ }
}
void LauncherWindow::showLinkHover(const QString &link, const QString &toolTip)
@@ -770,6 +806,16 @@ void LauncherWindow::toggleJavascriptCanOpenWindows(bool enable)
page()->settings()->setAttribute(QWebSettings::JavascriptCanOpenWindows, enable);
}
+void LauncherWindow::toggleAutoLoadImages(bool enable)
+{
+ page()->settings()->setAttribute(QWebSettings::AutoLoadImages, !enable);
+}
+
+void LauncherWindow::togglePlugins(bool enable)
+{
+ page()->settings()->setAttribute(QWebSettings::PluginsEnabled, !enable);
+}
+
#if defined(QT_CONFIGURED_WITH_OPENGL)
void LauncherWindow::toggleQGLWidgetViewport(bool enable)
{
@@ -874,6 +920,40 @@ void LauncherWindow::updateFPS(int fps)
#endif
}
+void LauncherWindow::toggleLocalStorage(bool toggle)
+{
+ m_windowOptions.useLocalStorage = toggle;
+ page()->settings()->setAttribute(QWebSettings::LocalStorageEnabled, toggle);
+}
+
+void LauncherWindow::toggleOfflineStorageDatabase(bool toggle)
+{
+ m_windowOptions.useOfflineStorageDatabase = toggle;
+ page()->settings()->setAttribute(QWebSettings::OfflineStorageDatabaseEnabled, toggle);
+}
+
+void LauncherWindow::toggleOfflineWebApplicationCache(bool toggle)
+{
+ m_windowOptions.useOfflineWebApplicationCache = toggle;
+ page()->settings()->setAttribute(QWebSettings::OfflineWebApplicationCacheEnabled, toggle);
+}
+
+void LauncherWindow::setOfflineStorageDefaultQuota()
+{
+ // For command line execution, quota size is taken from command line.
+ if (m_windowOptions.offlineStorageDefaultQuotaSize)
+ page()->settings()->setOfflineStorageDefaultQuota(m_windowOptions.offlineStorageDefaultQuotaSize);
+ else {
+#ifndef QT_NO_INPUTDIALOG
+ bool ok;
+ // Maximum size is set to 25 * 1024 * 1024.
+ int quotaSize = QInputDialog::getInt(this, "Offline Storage Default Quota Size" , "Quota Size", 0, 0, 26214400, 1, &ok);
+ if (ok)
+ page()->settings()->setOfflineStorageDefaultQuota(quotaSize);
+#endif
+ }
+}
+
LauncherWindow* LauncherWindow::newWindow()
{
LauncherWindow* mw = new LauncherWindow(&m_windowOptions);
diff --git a/Tools/QtTestBrowser/launcherwindow.h b/Tools/QtTestBrowser/launcherwindow.h
index 849b15d..e13858e 100644
--- a/Tools/QtTestBrowser/launcherwindow.h
+++ b/Tools/QtTestBrowser/launcherwindow.h
@@ -94,6 +94,10 @@ public:
, showFrameRate(false)
, resizesToContents(false)
, viewportUpdateMode(QGraphicsView::MinimalViewportUpdate)
+ , useLocalStorage(false)
+ , useOfflineStorageDatabase(false)
+ , useOfflineWebApplicationCache(false)
+ , offlineStorageDefaultQuotaSize(0)
#if defined(QT_CONFIGURED_WITH_OPENGL)
, useQGLWidgetViewport(false)
#endif
@@ -110,6 +114,10 @@ public:
bool showFrameRate;
bool resizesToContents;
QGraphicsView::ViewportUpdateMode viewportUpdateMode;
+ bool useLocalStorage;
+ bool useOfflineStorageDatabase;
+ bool useOfflineWebApplicationCache;
+ quint64 offlineStorageDefaultQuotaSize;
#if defined(QT_CONFIGURED_WITH_OPENGL)
bool useQGLWidgetViewport;
#endif
@@ -163,6 +171,12 @@ protected slots:
void toggleFrameFlattening(bool toggle);
void toggleInterruptingJavaScriptEnabled(bool enable);
void toggleJavascriptCanOpenWindows(bool enable);
+ void toggleAutoLoadImages(bool enable);
+ void togglePlugins(bool enable);
+ void toggleLocalStorage(bool toggle);
+ void toggleOfflineStorageDatabase(bool toggle);
+ void toggleOfflineWebApplicationCache(bool toggle);
+ void setOfflineStorageDefaultQuota();
#if defined(QT_CONFIGURED_WITH_OPENGL)
void toggleQGLWidgetViewport(bool enable);
@@ -206,6 +220,8 @@ private:
QPropertyAnimation* m_zoomAnimation;
QList<QTouchEvent::TouchPoint> m_touchPoints;
bool m_touchMocking;
+
+ QString m_inputUrl;
};
#endif
diff --git a/Tools/QtTestBrowser/locationedit.h b/Tools/QtTestBrowser/locationedit.h
index 752497e..962b422 100644
--- a/Tools/QtTestBrowser/locationedit.h
+++ b/Tools/QtTestBrowser/locationedit.h
@@ -28,6 +28,8 @@
#ifndef locationedit_h
#define locationedit_h
+#include <qconfig.h>
+
#ifndef QT_NO_INPUTDIALOG
#include <QtGui>
diff --git a/Tools/QtTestBrowser/main.cpp b/Tools/QtTestBrowser/main.cpp
index ec5f1d9..eecd9c3 100644
--- a/Tools/QtTestBrowser/main.cpp
+++ b/Tools/QtTestBrowser/main.cpp
@@ -164,18 +164,18 @@ void LauncherApplication::handleUserOptions()
}
if (args.contains("-local-storage-enabled"))
- QWebSettings::globalSettings()->setAttribute(QWebSettings::LocalStorageEnabled, true);
+ windowOptions.useLocalStorage = true;
if (args.contains("-offline-storage-database-enabled"))
- QWebSettings::globalSettings()->setAttribute(QWebSettings::OfflineStorageDatabaseEnabled, true);
+ windowOptions.useOfflineStorageDatabase = true;
if (args.contains("-offline-web-application-cache-enabled"))
- QWebSettings::globalSettings()->setAttribute(QWebSettings::OfflineWebApplicationCacheEnabled, true);
+ windowOptions.useOfflineWebApplicationCache = true;
int setOfflineStorageDefaultQuotaIndex = args.indexOf("-set-offline-storage-default-quota");
if (setOfflineStorageDefaultQuotaIndex != -1) {
- int maxSize = takeOptionValue(&args, setOfflineStorageDefaultQuotaIndex).toInt();
- QWebSettings::globalSettings()->setOfflineStorageDefaultQuota(maxSize);
+ unsigned int maxSize = takeOptionValue(&args, setOfflineStorageDefaultQuotaIndex).toUInt();
+ windowOptions.offlineStorageDefaultQuotaSize = maxSize;
}
if (defaultForAnimations)
diff --git a/Tools/QtTestBrowser/mainwindow.cpp b/Tools/QtTestBrowser/mainwindow.cpp
index 9f4aec5..e2ea41d 100644
--- a/Tools/QtTestBrowser/mainwindow.cpp
+++ b/Tools/QtTestBrowser/mainwindow.cpp
@@ -171,6 +171,14 @@ void MainWindow::load(const QUrl& url)
page()->mainFrame()->load(url);
}
+QString MainWindow::addressUrl() const
+{
+#ifndef QT_NO_INPUTDIALOG
+ return urlEdit->text();
+#endif
+ return QString();
+}
+
void MainWindow::changeLocation()
{
#ifndef QT_NO_INPUTDIALOG
diff --git a/Tools/QtTestBrowser/mainwindow.h b/Tools/QtTestBrowser/mainwindow.h
index 3a39d57..08fa81e 100644
--- a/Tools/QtTestBrowser/mainwindow.h
+++ b/Tools/QtTestBrowser/mainwindow.h
@@ -59,6 +59,9 @@ protected slots:
void openLocation();
void changeLocation();
+protected:
+ QString addressUrl() const;
+
private:
void buildUI();
diff --git a/Tools/QueueStatusServer/templates/submittoews.html b/Tools/QueueStatusServer/templates/submittoews.html
index fb9d8aa..935d7bb 100644
--- a/Tools/QueueStatusServer/templates/submittoews.html
+++ b/Tools/QueueStatusServer/templates/submittoews.html
@@ -1,3 +1,3 @@
<form name="submit_to_ews" enctype="multipart/form-data" method="post">
-Patch to submit: <input name="attachment_id"><input type="submit" value="Submit for EWS Processing"></div>
+Attachment id of patch to submit: <input name="attachment_id"><input type="submit" value="Submit for EWS Processing"></div>
</form>
diff --git a/Tools/Scripts/build-webkit b/Tools/Scripts/build-webkit
index 0b58113..74015ec 100755
--- a/Tools/Scripts/build-webkit
+++ b/Tools/Scripts/build-webkit
@@ -85,12 +85,14 @@ my (
$javaScriptDebuggerSupport,
$linkPrefetchSupport,
$mathmlSupport,
+ $mediaStatisticsSupport,
$meterTagSupport,
$netscapePluginSupport,
$notificationsSupport,
$offlineWebApplicationSupport,
$orientationEventsSupport,
$progressTagSupport,
+ $registerProtocolHandlerSupport,
$sharedWorkersSupport,
$svgSupport,
$svgAnimationSupport,
@@ -116,8 +118,8 @@ my (
);
my @features = (
- { option => "3d-canvas", desc => "Toggle 3D canvas support",
- define => "ENABLE_3D_CANVAS", default => (isAppleMacWebKit() && !isTiger() && !isLeopard()), value => \$threeDCanvasSupport },
+ { option => "3d-canvas", desc => "Toggle 3D canvas (WebGL) support",
+ define => "ENABLE_WEBGL", default => (isAppleMacWebKit() && !isTiger() && !isLeopard()), value => \$threeDCanvasSupport },
{ option => "3d-rendering", desc => "Toggle 3D rendering support",
define => "ENABLE_3D_RENDERING", default => (isAppleMacWebKit() && !isTiger()), value => \$threeDRenderingSupport },
@@ -194,6 +196,9 @@ my @features = (
{ option => "mathml", desc => "Toggle MathML support",
define => "ENABLE_MATHML", default => 1, value => \$mathmlSupport },
+ { option => "media-statistics", desc => "Toggle Media Statistics support",
+ define => "ENABLE_MEDIA_STATISTICS", default => 0, value => \$mediaStatisticsSupport },
+
{ option => "meter-tag", desc => "Meter Tag support",
define => "ENABLE_METER_TAG", default => !isGtk() && !isAppleWinWebKit(), value => \$meterTagSupport },
@@ -212,6 +217,9 @@ my @features = (
{ option => "progress-tag", desc => "Progress Tag support",
define => "ENABLE_PROGRESS_TAG", default => 1, value => \$progressTagSupport },
+ { option => "register-protocol-handler", desc => "Register Protocol Handler support",
+ define => "ENABLE_REGISTER_PROTOCOL_HANDLER", default => 0, value => \$registerProtocolHandlerSupport },
+
{ option => "system-malloc", desc => "Toggle system allocator instead of TCmalloc",
define => "USE_SYSTEM_MALLOC", default => 0, value => \$systemMallocSupport },
@@ -405,7 +413,7 @@ if (isGtk()) {
{
my ($feature, $isEnabled, $defaultValue) = @_;
return "" if $defaultValue == $isEnabled;
- return $feature . "=" . ($isEnabled ? $feature : " ");
+ return $feature . "=" . ($isEnabled ? $feature : "");
}
foreach (@features) {
diff --git a/Tools/Scripts/check-inspector-strings b/Tools/Scripts/check-inspector-strings
index 82c08d7..0350aca 100755
--- a/Tools/Scripts/check-inspector-strings
+++ b/Tools/Scripts/check-inspector-strings
@@ -54,6 +54,9 @@ class StringsExtractor(ProcessorBase):
def should_process(self, file_path):
return file_path.endswith(".js") and (not file_path.endswith("InjectedScript.js"))
+ def decode_unicode_escapes(self, s):
+ return eval("ur\"" + s + "\"")
+
def process(self, lines, file_path, line_numbers=None):
for line in lines:
comment_start = line.find("//")
@@ -63,7 +66,7 @@ class StringsExtractor(ProcessorBase):
for pattern in self._patterns:
line_strings = re.findall(pattern, line)
for string in line_strings:
- self.strings[index].append(string)
+ self.strings[index].append(self.decode_unicode_escapes(string))
index += 1
class LocalizedStringsExtractor:
@@ -113,3 +116,10 @@ if __name__ == "__main__":
unused_strings = old_strings - strings
for s in unused_strings:
_log.info("Unused: \"%s\"" % (s))
+
+ localized_strings_duplicates = {}
+ for s in localized_strings_extractor.localized_strings:
+ if s in localized_strings_duplicates:
+ _log.info("Duplicate: \"%s\"" % (s))
+ else:
+ localized_strings_duplicates.setdefault(s)
diff --git a/Tools/Scripts/do-webcore-rename b/Tools/Scripts/do-webcore-rename
index aaa1eee..6dbfc1f 100755
--- a/Tools/Scripts/do-webcore-rename
+++ b/Tools/Scripts/do-webcore-rename
@@ -72,7 +72,7 @@ my @paths;
find(\&wanted, "Source/JavaScriptCore");
find(\&wanted, "Source/JavaScriptGlue");
find(\&wanted, "Source/WebCore");
-find(\&wanted, "WebKit");
+find(\&wanted, "Source/WebKit");
find(\&wanted, "Source/WebKit2");
find(\&wanted, "Tools/DumpRenderTree");
diff --git a/Tools/Scripts/old-run-webkit-tests b/Tools/Scripts/old-run-webkit-tests
index 79e2d9e..c56cb1c 100755
--- a/Tools/Scripts/old-run-webkit-tests
+++ b/Tools/Scripts/old-run-webkit-tests
@@ -77,6 +77,7 @@ use POSIX;
sub buildPlatformResultHierarchy();
sub buildPlatformTestHierarchy(@);
+sub captureSavedCrashLog($);
sub checkPythonVersion();
sub closeCygpaths();
sub closeDumpTool();
@@ -89,6 +90,7 @@ sub dumpToolDidCrash();
sub epiloguesAndPrologues($$);
sub expectedDirectoryForTest($;$;$);
sub fileNameWithNumber($$);
+sub findNewestFileMatchingGlob($);
sub htmlForResultsSection(\@$&);
sub isTextOnlyTest($);
sub launchWithEnv(\@\%);
@@ -189,6 +191,9 @@ my $actualTag = "actual";
my $prettyDiffTag = "pretty-diff";
my $diffsTag = "diffs";
my $errorTag = "stderr";
+my $crashLogTag = "crash-log";
+
+my $windowsCrashLogFilePrefix = "CrashLog";
# These are defined here instead of closer to where they are used so that they
# will always be accessible from the END block that uses them, even if the user
@@ -1731,7 +1736,9 @@ sub testCrashedOrTimedOut($$$$$$)
kill 9, $dumpToolPID unless $didCrash;
closeDumpTool();
-
+
+ captureSavedCrashLog($base) if $didCrash;
+
return unless isCygwin() && !$didCrash && $base =~ /^http/;
# On Cygwin, http tests timing out can be a symptom of a non-responsive httpd.
# If we timed out running an http test, try restarting httpd.
@@ -1739,6 +1746,51 @@ sub testCrashedOrTimedOut($$$$$$)
configureAndOpenHTTPDIfNeeded();
}
+sub captureSavedCrashLog($)
+{
+ my ($base) = @_;
+
+ my $crashLog;
+
+ my $glob;
+ if (isCygwin()) {
+ $glob = File::Spec->catfile($testResultsDirectory, $windowsCrashLogFilePrefix . "*.txt");
+ } elsif (isAppleMacWebKit()) {
+ $glob = File::Spec->catfile("~", "Library", "Logs", "CrashReporter", $dumpToolName . "_*.crash");
+
+ # Even though the dump tool has exited, CrashReporter might still be running. We need to
+ # wait for it to exit to ensure it has saved its crash log to disk. For simplicitly, we'll
+ # assume that the ReportCrash process with the highest PID is the one we want.
+ if (my @reportCrashPIDs = sort map { /^\s*(\d+)/; $1 } grep { /ReportCrash/ } `/bin/ps x`) {
+ my $reportCrashPID = $reportCrashPIDs[$#reportCrashPIDs];
+ # We use kill instead of waitpid because ReportCrash is not one of our child processes.
+ usleep(250000) while kill(0, $reportCrashPID) > 0;
+ }
+ }
+
+ # We assume that the newest crash log in matching the glob is the one that corresponds to the crash that just occurred.
+ if (my $newestCrashLog = findNewestFileMatchingGlob($glob)) {
+ # The crash log must have been created after this script started running.
+ $crashLog = $newestCrashLog if -M $newestCrashLog < 0;
+ }
+
+ return unless $crashLog;
+
+ move($crashLog, File::Spec->catfile($testResultsDirectory, "$base-$crashLogTag.txt"));
+}
+
+sub findNewestFileMatchingGlob($)
+{
+ my ($glob) = @_;
+
+ my @paths = glob $glob;
+ return unless @paths;
+
+ my @pathsAndTimes = map { [$_, -M $_] } @paths;
+ @pathsAndTimes = sort { $b->[1] <=> $a->[1] } @pathsAndTimes;
+ return $pathsAndTimes[$#pathsAndTimes]->[0];
+}
+
sub printFailureMessageForTest($$)
{
my ($test, $description) = @_;
@@ -1865,7 +1917,9 @@ sub htmlForResultsSection(\@$&)
push @html, "<tr>";
push @html, "<td><a href=\"" . toURL("$testDirectory/$test") . "\">$test</a></td>";
foreach my $link (@{&{$linkGetter}($test)}) {
- push @html, "<td><a href=\"$link->{href}\">$link->{text}</a></td>";
+ push @html, "<td>";
+ push @html, "<a href=\"$link->{href}\">$link->{text}</a>" if -f File::Spec->catfile($testResultsDirectory, $link->{href});
+ push @html, "</td>";
}
push @html, "</tr>";
}
@@ -1911,6 +1965,63 @@ sub linksForMismatchTest
return \@links;
}
+sub crashLocation($)
+{
+ my ($base) = @_;
+
+ my $crashLogFile = File::Spec->catfile($testResultsDirectory, "$base-$crashLogTag.txt");
+
+ if (isCygwin()) {
+ # We're looking for the following text:
+ #
+ # FOLLOWUP_IP:
+ # module!function+offset [file:line]
+ #
+ # The second contains the function that crashed (or the function that ended up jumping to a bad
+ # address, as in the case of a null function pointer).
+
+ open LOG, "<", $crashLogFile or return;
+ while (my $line = <LOG>) {
+ last if $line =~ /^FOLLOWUP_IP:/;
+ }
+ my $desiredLine = <LOG>;
+ close LOG;
+
+ return unless $desiredLine;
+
+ # Just take everything up to the first space (which is where the file/line information should
+ # start).
+ $desiredLine =~ /^(\S+)/;
+ return $1;
+ }
+
+ if (isAppleMacWebKit()) {
+ # We're looking for the following text:
+ #
+ # Thread M Crashed:
+ # N module address function + offset (file:line)
+ #
+ # Some lines might have a module of "???" if we've jumped to a bad address. We should skip
+ # past those.
+
+ open LOG, "<", $crashLogFile or return;
+ while (my $line = <LOG>) {
+ last if $line =~ /^Thread \d+ Crashed:/;
+ }
+ my $location;
+ while (my $line = <LOG>) {
+ $line =~ /^\d+\s+(\S+)\s+\S+ (.* \+ \d+)/ or next;
+ my $module = $1;
+ my $functionAndOffset = $2;
+ next if $module eq "???";
+ $location = "$module: $functionAndOffset";
+ last;
+ }
+ close LOG;
+ return $location;
+ }
+}
+
sub linksForErrorTest
{
my ($test) = @_;
@@ -1919,8 +2030,14 @@ sub linksForErrorTest
my $base = stripExtension($test);
+ my $crashLogText = "crash log";
+ if (my $crashLocation = crashLocation($base)) {
+ $crashLogText .= " (<code>" . $crashLocation . "</code>)";
+ }
+
push @links, @{linksForExpectedAndActualResults($base)};
push @links, { href => "$base-$errorTag.txt", text => "stderr" };
+ push @links, { href => "$base-$crashLogTag.txt", text => $crashLogText };
return \@links;
}
@@ -1951,6 +2068,7 @@ sub deleteExpectedAndActualResults($)
unlink "$testResultsDirectory/$base-$actualTag.txt";
unlink "$testResultsDirectory/$base-$diffsTag.txt";
unlink "$testResultsDirectory/$base-$errorTag.txt";
+ unlink "$testResultsDirectory/$base-$crashLogTag.txt";
}
sub recordActualResultsAndDiff($$)
@@ -2450,6 +2568,37 @@ sub stopRunningTestsEarlyIfNeeded()
return 0;
}
+# Store this at global scope so it won't be GCed (and thus unlinked) until the program exits.
+my $debuggerTempDirectory;
+
+sub createDebuggerCommandFile()
+{
+ return unless isCygwin();
+
+ my @commands = (
+ '.logopen /t "' . toWindowsPath($testResultsDirectory) . "\\" . $windowsCrashLogFilePrefix . '.txt"',
+ '.srcpath "' . toWindowsPath(sourceDir()) . '"',
+ '!analyze -vv',
+ '~*kpn',
+ 'q',
+ );
+
+ $debuggerTempDirectory = File::Temp->newdir;
+
+ my $commandFile = File::Spec->catfile($debuggerTempDirectory, "debugger-commands.txt");
+ unless (open COMMANDS, '>', $commandFile) {
+ print "Failed to open $commandFile. Crash logs will not be saved.\n";
+ return;
+ }
+ print COMMANDS join("\n", @commands), "\n";
+ unless (close COMMANDS) {
+ print "Failed to write to $commandFile. Crash logs will not be saved.\n";
+ return;
+ }
+
+ return $commandFile;
+}
+
sub setUpWindowsCrashLogSaving()
{
return unless isCygwin();
@@ -2468,8 +2617,23 @@ sub setUpWindowsCrashLogSaving()
}
}
+ # If we used -c (instead of -cf) we could pass the commands directly on the command line. But
+ # when the commands include multiple quoted paths (e.g., for .logopen and .srcpath), Windows
+ # fails to invoke the post-mortem debugger at all (perhaps due to a bug in Windows's command
+ # line parsing). So we save the commands to a file instead and tell the debugger to execute them
+ # using -cf.
+ my $commandFile = createDebuggerCommandFile() or return;
+
+ my @options = (
+ '-p %ld',
+ '-e %ld',
+ '-g',
+ '-lines',
+ '-cf "' . toWindowsPath($commandFile) . '"',
+ );
+
my %values = (
- Debugger => '"' . toWindowsPath($ntsdPath) . '" -p %ld -e %ld -g -lines -c ".logopen /t \"' . toWindowsPath($testResultsDirectory) . '\CrashLog.txt\";!analyze -vv;~*kpn;q"',
+ Debugger => '"' . toWindowsPath($ntsdPath) . '" ' . join(' ', @options),
Auto => 1
);
diff --git a/Tools/Scripts/rebaseline-chromium-webkit-tests b/Tools/Scripts/rebaseline-chromium-webkit-tests
index 8d14b86..806ca17 100755
--- a/Tools/Scripts/rebaseline-chromium-webkit-tests
+++ b/Tools/Scripts/rebaseline-chromium-webkit-tests
@@ -41,4 +41,4 @@ sys.path.append(os.path.join(webkitpy_directory, "thirdparty"))
import rebaseline_chromium_webkit_tests
if __name__ == '__main__':
- rebaseline_chromium_webkit_tests.main()
+ rebaseline_chromium_webkit_tests.main(sys.argv[1:])
diff --git a/Tools/Scripts/run-chromium-webkit-unit-tests b/Tools/Scripts/run-chromium-webkit-unit-tests
index 62646af..1e2b0aa 100755
--- a/Tools/Scripts/run-chromium-webkit-unit-tests
+++ b/Tools/Scripts/run-chromium-webkit-unit-tests
@@ -41,9 +41,9 @@ setConfiguration();
my $pathToBinary;
if (isDarwin()) {
- $pathToBinary = "WebKit/chromium/xcodebuild/" . configuration() . "/webkit_unit_tests";
+ $pathToBinary = "Source/WebKit/chromium/xcodebuild/" . configuration() . "/webkit_unit_tests";
} elsif (isCygwin() || isWindows()) {
- $pathToBinary = "WebKit/chromium/" . configuration() . "/webkit_unit_tests.exe";
+ $pathToBinary = "Source/WebKit/chromium/" . configuration() . "/webkit_unit_tests.exe";
} elsif (isLinux()) {
$pathToBinary = "out/" . configuration() . "/webkit_unit_tests";
}
diff --git a/Tools/Scripts/run-webkit-httpd b/Tools/Scripts/run-webkit-httpd
index 9ea2551..31b469e 100755
--- a/Tools/Scripts/run-webkit-httpd
+++ b/Tools/Scripts/run-webkit-httpd
@@ -2,6 +2,7 @@
# Copyright (C) 2005, 2006, 2007 Apple Inc. All rights reserved.
# Copyright (C) 2006 Alexey Proskuryakov (ap@nypop.com)
+# Copyright (C) 2011 Research In Motion Limited. All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
@@ -69,6 +70,7 @@ setConfiguration();
my $productDir = productDir();
chdirWebKit();
my $testDirectory = File::Spec->catfile(getcwd(), "LayoutTests");
+$testDirectory = convertMsysPath($testDirectory) if isMsys();
my $listen = "127.0.0.1:$httpdPort";
$listen = "$httpdPort" if ($allInterfaces);
@@ -82,14 +84,16 @@ print "Press Ctrl+C to stop it.\n\n";
my @args = (
"-C", "Listen $listen",
- "-c", "CustomLog |/usr/bin/tee common",
- "-c", "ErrorLog |/usr/bin/tee",
- # Run in single-process mode, do not detach from the controlling terminal.
- "-X",
# Disable Keep-Alive support. Makes testing in multiple browsers easier (no need to wait
# for another browser's connection to expire).
"-c", "KeepAlive 0"
);
+push @args, (
+ "-c", "CustomLog |/usr/bin/tee common",
+ "-c", "ErrorLog |/usr/bin/tee",
+ # Run in single-process mode, do not detach from the controlling terminal.
+ "-X",
+) unless isMsys();
my @defaultArgs = getDefaultConfigForTestDirectory($testDirectory);
@args = (@defaultArgs, @args);
diff --git a/Tools/Scripts/update-webkit b/Tools/Scripts/update-webkit
index 6d3e0ee..aca56b8 100755
--- a/Tools/Scripts/update-webkit
+++ b/Tools/Scripts/update-webkit
@@ -50,9 +50,6 @@ determineIsChromium();
chdirWebKit();
-my $isGit = isGit();
-my $isSVN = isSVN();
-
my $getOptionsResult = GetOptions(
'h|help' => \$showHelp,
'q|quiet' => \$quiet,
@@ -77,14 +74,14 @@ push @svnOptions, '-q' if $quiet;
push @svnOptions, qw(--accept postpone) if isSVNVersion16OrNewer();
print "Updating OpenSource\n" unless $quiet;
-runSvnUpdate() if $isSVN;
-runGitUpdate() if $isGit;
+runSvnUpdate() if isSVN();
+runGitUpdate() if isGit();
if (-d "../Internal") {
chdir("../Internal");
print "Updating Internal\n" unless $quiet;
- runSvnUpdate() if $isSVN;
- runGitUpdate() if $isGit;
+ runSvnUpdate() if isSVN();
+ runGitUpdate() if isGit();
} elsif (isChromium()) {
# Workaround for https://bugs.webkit.org/show_bug.cgi?id=38926
# We should remove the following "if" block when we find a right fix.
diff --git a/Tools/Scripts/webkit-patch b/Tools/Scripts/webkit-patch
index 007f919..1eb8476 100755
--- a/Tools/Scripts/webkit-patch
+++ b/Tools/Scripts/webkit-patch
@@ -33,6 +33,7 @@
import logging
import os
+import signal
import sys
from webkitpy.common.system.logutils import configure_logging
@@ -66,5 +67,7 @@ def main():
if __name__ == "__main__":
-
- main()
+ try:
+ main()
+ except KeyboardInterrupt:
+ sys.exit(signal.SIGINT + 128)
diff --git a/Tools/Scripts/webkitdirs.pm b/Tools/Scripts/webkitdirs.pm
index 0ead831..aa7bab7 100644
--- a/Tools/Scripts/webkitdirs.pm
+++ b/Tools/Scripts/webkitdirs.pm
@@ -356,7 +356,7 @@ sub productDir
sub jscProductDir
{
my $productDir = productDir();
- $productDir .= "/Source/JavaScriptCore" if isQt();
+ $productDir .= "/JavaScriptCore" if isQt();
$productDir .= "/$configuration" if (isQt() && isWindows());
$productDir .= "/Programs" if (isGtk() || isEfl());
@@ -1009,14 +1009,18 @@ sub checkRequiredSystemConfig
{
if (isDarwin()) {
chomp(my $productVersion = `sw_vers -productVersion`);
- if ($productVersion lt "10.4") {
+ if (eval "v$productVersion" lt v10.4) {
print "*************************************************************\n";
print "Mac OS X Version 10.4.0 or later is required to build WebKit.\n";
print "You have " . $productVersion . ", thus the build will most likely fail.\n";
print "*************************************************************\n";
}
- my $xcodeVersion = `xcodebuild -version`;
- if ($xcodeVersion !~ /DevToolsCore-(\d+)/ || $1 < 747) {
+ my $xcodebuildVersionOutput = `xcodebuild -version`;
+ my $devToolsCoreVersion = ($xcodebuildVersionOutput =~ /DevToolsCore-(\d+)/) ? $1 : undef;
+ my $xcodeVersion = ($xcodebuildVersionOutput =~ /Xcode ([0-9](\.[0-9]+)*)/) ? $1 : undef;
+ if (!$devToolsCoreVersion && !$xcodeVersion
+ || $devToolsCoreVersion && $devToolsCoreVersion < 747
+ || $xcodeVersion && eval "v$xcodeVersion" lt v2.3) {
print "*************************************************************\n";
print "Xcode Version 2.3 or later is required to build WebKit.\n";
print "You have an earlier version of Xcode, thus the build will\n";
@@ -1501,7 +1505,7 @@ sub buildCMakeProject($@)
push @buildArgs, "-DCMAKE_BUILD_TYPE=Release";
}
- push @buildArgs, sourceDir();
+ push @buildArgs, sourceDir() . "/Source";
$dir = File::Spec->catfile($dir, $config);
File::Path::mkpath($dir);
@@ -1571,6 +1575,13 @@ sub buildQMakeProject($@)
push @buildArgs, "INSTALL_HEADERS=" . $installHeaders if defined($installHeaders);
push @buildArgs, "INSTALL_LIBS=" . $installLibs if defined($installLibs);
my $dir = File::Spec->canonpath(productDir());
+
+
+ # On Symbian qmake needs to run in the same directory where the pro file is located.
+ if (isSymbian()) {
+ $dir = $sourceDir . "/Source";
+ }
+
File::Path::mkpath($dir);
chdir $dir or die "Failed to cd into " . $dir . "\n";
@@ -1580,7 +1591,7 @@ sub buildQMakeProject($@)
my @dsQmakeArgs = @buildArgs;
push @dsQmakeArgs, "-r";
- push @dsQmakeArgs, sourceDir() . "/DerivedSources.pro";
+ push @dsQmakeArgs, sourceDir() . "/Source/DerivedSources.pro";
push @dsQmakeArgs, "-o Makefile.DerivedSources";
print "Calling '$qmakebin @dsQmakeArgs' in " . $dir . "\n\n";
my $result = system "$qmakebin @dsQmakeArgs";
@@ -1588,18 +1599,29 @@ sub buildQMakeProject($@)
die "Failed while running $qmakebin to generate derived sources!\n";
}
- my $dsMakefile = "Makefile.DerivedSources";
-
- # Iterate over different source directories manually to workaround a problem with qmake+extraTargets+s60
- my @subdirs = ("Source/JavaScriptCore", "Source/WebCore", "Source/WebKit/qt/Api");
+ # FIXME: Iterate over different source directories manually to workaround a problem with qmake+extraTargets+s60
+ # To avoid overwriting of Makefile.DerivedSources in the root dir use Makefile.DerivedSources.Tools for Tools
+ my @subdirs = ("JavaScriptCore", "WebCore", "WebKit/qt/Api");
if (grep { $_ eq "CONFIG+=webkit2"} @buildArgs) {
- push @subdirs, "Source/WebKit2";
- push @subdirs, "Tools/WebKitTestRunner";
- push @subdirs, "Tools/MiniBrowser";
+ push @subdirs, "WebKit2";
+ if ( -e sourceDir() ."/Tools/DerivedSources.pro" ) {
+ @dsQmakeArgs = @buildArgs;
+ push @dsQmakeArgs, "-r";
+ push @dsQmakeArgs, sourceDir() . "/Tools/DerivedSources.pro";
+ push @dsQmakeArgs, "-o Makefile.DerivedSources.Tools";
+ print "Calling '$qmakebin @dsQmakeArgs' in " . $dir . "\n\n";
+ my $result = system "$qmakebin @dsQmakeArgs";
+ if ($result ne 0) {
+ die "Failed while running $qmakebin to generate derived sources for Tools!\n";
+ }
+ push @subdirs, "MiniBrowser";
+ push @subdirs, "WebKitTestRunner";
+ }
}
for my $subdir (@subdirs) {
- print "Calling '$make $makeargs -f $dsMakefile generated_files' in " . $dir . "/$subdir\n\n";
+ my $dsMakefile = "Makefile.DerivedSources";
+ print "Calling '$make $makeargs -C $subdir -f $dsMakefile generated_files' in " . $dir . "/$subdir\n\n";
if ($make eq "nmake") {
my $subdirWindows = $subdir;
$subdirWindows =~ s:/:\\:g;
@@ -1626,8 +1648,7 @@ sub buildQMakeProject($@)
}
}
- push @buildArgs, sourceDir() . "/WebKit.pro";
-
+ push @buildArgs, sourceDir() . "/Source/WebKit.pro";
print "Calling '$qmakebin @buildArgs' in " . $dir . "\n\n";
print "Installation headers directory: $installHeaders\n" if(defined($installHeaders));
print "Installation libraries directory: $installLibs\n" if(defined($installLibs));
@@ -1637,8 +1658,24 @@ sub buildQMakeProject($@)
die "Failed to setup build environment using $qmakebin!\n";
}
+ $buildArgs[-1] = sourceDir() . "/Tools/Tools.pro";
+ my $makefile = "Makefile.Tools";
+
+ # On Symbian qmake needs to run in the same directory where the pro file is located.
+ if (isSymbian()) {
+ $dir = $sourceDir . "/Tools";
+ chdir $dir or die "Failed to cd into " . $dir . "\n";
+ $makefile = "bld.inf";
+ }
+
+ print "Calling '$qmakebin @buildArgs -o $makefile' in " . $dir . "\n\n";
+ $result = system "$qmakebin @buildArgs -o $makefile";
+ if ($result ne 0) {
+ die "Failed to setup build environment using $qmakebin!\n";
+ }
+
# Manually create makefiles for the examples so we don't build by default
- my $examplesDir = $dir . "/Source/WebKit/qt/examples";
+ my $examplesDir = $dir . "/WebKit/qt/examples";
File::Path::mkpath($examplesDir);
$buildArgs[-1] = sourceDir() . "/Source/WebKit/qt/examples/examples.pro";
chdir $examplesDir or die;
@@ -1647,9 +1684,16 @@ sub buildQMakeProject($@)
die "Failed to create makefiles for the examples!\n" if $result ne 0;
chdir $dir or die;
+ my $makeTools = "echo No Makefile for Tools. Skipping make";
+
+ if (-e "$dir/$makefile") {
+ $makeTools = "$make $makeargs -f $makefile";
+ }
+
if ($clean) {
print "Calling '$make $makeargs distclean' in " . $dir . "\n\n";
$result = system "$make $makeargs distclean";
+ $result = $result || system "$makeTools distclean";
} elsif (isSymbian()) {
print "\n\nWebKit is now configured for building, but you have to make\n";
print "a choice about the target yourself. To start the build run:\n\n";
@@ -1657,6 +1701,7 @@ sub buildQMakeProject($@)
} else {
print "Calling '$make $makeargs' in " . $dir . "\n\n";
$result = system "$make $makeargs";
+ $result = $result || system "$makeTools";
}
chdir ".." or die;
diff --git a/Tools/Scripts/webkitperl/httpd.pm b/Tools/Scripts/webkitperl/httpd.pm
index b415db6..b73904d 100644
--- a/Tools/Scripts/webkitperl/httpd.pm
+++ b/Tools/Scripts/webkitperl/httpd.pm
@@ -1,6 +1,7 @@
# Copyright (C) 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved
# Copyright (C) 2006 Alexey Proskuryakov (ap@nypop.com)
# Copyright (C) 2010 Andras Becsi (abecsi@inf.u-szeged.hu), University of Szeged
+# Copyright (C) 2011 Research In Motion Limited. All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
@@ -58,6 +59,7 @@ BEGIN {
}
my $tmpDir = "/tmp";
+$tmpDir = convertMsysPath($tmpDir) if isMsys();
my $httpdLockPrefix = "WebKitHttpd.lock.";
my $myLockFile;
my $exclusiveLockFile = File::Spec->catfile($tmpDir, "WebKit.lock");
@@ -76,6 +78,8 @@ sub getHTTPDPath
{
if (isDebianBased()) {
$httpdPath = "/usr/sbin/apache2";
+ } elsif (isMsys()) {
+ $httpdPath = 'c:\program files\apache software foundation\apache2.2\bin\httpd.exe';
} else {
$httpdPath = "/usr/sbin/httpd";
}
@@ -100,13 +104,16 @@ sub getDefaultConfigForTestDirectory
# Setup a link to where the js test templates are stored, use -c so that mod_alias will already be loaded.
"-c", "Alias /js-test-resources \"$jsTestResourcesDirectory\"",
"-c", "TypesConfig \"$typesConfig\"",
- # Apache wouldn't run CGIs with permissions==700 otherwise
- "-c", "User \"#$<\"",
- "-c", "LockFile \"$httpdLockFile\"",
"-c", "PidFile \"$httpdPidFile\"",
"-c", "ScoreBoardFile \"$httpdScoreBoardFile\"",
);
+ push @httpdArgs, (
+ # Apache wouldn't run CGIs with permissions==700 otherwise
+ "-c", "User \"#$<\"",
+ "-c", "LockFile \"$httpdLockFile\""
+ ) unless isMsys();
+
# FIXME: Enable this on Windows once <rdar://problem/5345985> is fixed
# The version of Apache we use with Cygwin does not support SSL
my $sslCertificate = "$testDirectory/http/conf/webkit-httpd.pem";
@@ -129,6 +136,8 @@ sub getHTTPDConfigPathForTestDirectory
chmod(0755, "/usr/lib/apache/libphp4.dll");
}
$httpdConfig = "$windowsConfDirectory/cygwin-httpd.conf";
+ } elsif (isMsys()) {
+ $httpdConfig = "$testDirectory/http/conf/apache2-msys-httpd.conf";
} elsif (isDebianBased()) {
$httpdConfig = "$testDirectory/http/conf/apache2-debian-httpd.conf";
} elsif (isFedoraBased()) {
@@ -319,3 +328,13 @@ sub getWaitTime
}
return $waitTime;
}
+
+sub convertMsysPath
+{
+ my ($path) = @_;
+ return unless isMsys();
+
+ $path = `cmd.exe //c echo $path`;
+ $path =~ s/\r\n$//;
+ return $path;
+}
diff --git a/Tools/Scripts/webkitpy/common/checkout/api.py b/Tools/Scripts/webkitpy/common/checkout/api.py
index a87bb5a..170b822 100644
--- a/Tools/Scripts/webkitpy/common/checkout/api.py
+++ b/Tools/Scripts/webkitpy/common/checkout/api.py
@@ -33,6 +33,7 @@ from webkitpy.common.config import urls
from webkitpy.common.checkout.changelog import ChangeLog
from webkitpy.common.checkout.commitinfo import CommitInfo
from webkitpy.common.checkout.scm import CommitMessage
+from webkitpy.common.checkout.deps import DEPS
from webkitpy.common.memoized import memoized
from webkitpy.common.net.bugzilla import parse_bug_id
from webkitpy.common.system.executive import Executive, run_command, ScriptError
@@ -148,6 +149,9 @@ class Checkout(object):
except ScriptError, e:
pass # We might not have ChangeLogs.
+ def chromium_deps(self):
+ return DEPS(os.path.join(self._scm.checkout_root, "Source", "WebKit", "chromium", "DEPS"))
+
def apply_patch(self, patch, force=False):
# It's possible that the patch was not made from the root directory.
# We should detect and handle that case.
diff --git a/Tools/Scripts/webkitpy/common/checkout/changelog.py b/Tools/Scripts/webkitpy/common/checkout/changelog.py
index 07f905d..c81318c 100644
--- a/Tools/Scripts/webkitpy/common/checkout/changelog.py
+++ b/Tools/Scripts/webkitpy/common/checkout/changelog.py
@@ -36,9 +36,7 @@ import textwrap
from webkitpy.common.system.deprecated_logging import log
from webkitpy.common.config.committers import CommitterList
-from webkitpy.common.config import urls
from webkitpy.common.net.bugzilla import parse_bug_id
-from webkitpy.tool.grammar import join_with_separators
class ChangeLogEntry(object):
@@ -145,29 +143,14 @@ class ChangeLog(object):
lines = [self._wrap_line(line) for line in message.splitlines()]
return "\n".join(lines)
- # This probably does not belong in changelogs.py
- def _message_for_revert(self, revision_list, reason, bug_url):
- message = "Unreviewed, rolling out %s.\n" % join_with_separators(['r' + str(revision) for revision in revision_list])
- for revision in revision_list:
- message += "%s\n" % urls.view_revision_url(revision)
- if bug_url:
- message += "%s\n" % bug_url
- # Add an extra new line after the rollout links, before any reason.
- message += "\n"
- if reason:
- message += "%s\n\n" % reason
- return self._wrap_lines(message)
-
- def update_for_revert(self, revision_list, reason, bug_url=None):
+ def update_with_unreviewed_message(self, message):
reviewed_by_regexp = re.compile(
"%sReviewed by NOBODY \(OOPS!\)\." % self._changelog_indent)
removing_boilerplate = False
# inplace=1 creates a backup file and re-directs stdout to the file
for line in fileinput.FileInput(self.path, inplace=1):
if reviewed_by_regexp.search(line):
- message_lines = self._message_for_revert(revision_list,
- reason,
- bug_url)
+ message_lines = self._wrap_lines(message)
print reviewed_by_regexp.sub(message_lines, line),
# Remove all the ChangeLog boilerplate between the Reviewed by
# line and the first changed file.
diff --git a/Tools/Scripts/webkitpy/common/checkout/changelog_unittest.py b/Tools/Scripts/webkitpy/common/checkout/changelog_unittest.py
index 20c6cfa..299d509 100644
--- a/Tools/Scripts/webkitpy/common/checkout/changelog_unittest.py
+++ b/Tools/Scripts/webkitpy/common/checkout/changelog_unittest.py
@@ -142,89 +142,3 @@ class ChangeLogTest(unittest.TestCase):
expected_contents = changelog_contents.replace("Need a short description and bug URL (OOPS!)", expected_message)
os.remove(changelog_path)
self.assertEquals(actual_contents, expected_contents)
-
- _revert_message = """ Unreviewed, rolling out r12345.
- http://trac.webkit.org/changeset/12345
- http://example.com/123
-
- This is a very long reason which should be long enough so that
- _message_for_revert will need to wrap it. We'll also include
- a
- https://veryveryveryveryverylongbugurl.com/reallylongbugthingy.cgi?bug_id=12354
- link so that we can make sure we wrap that right too.
-"""
-
- def test_message_for_revert(self):
- changelog = ChangeLog("/fake/path")
- long_reason = "This is a very long reason which should be long enough so that _message_for_revert will need to wrap it. We'll also include a https://veryveryveryveryverylongbugurl.com/reallylongbugthingy.cgi?bug_id=12354 link so that we can make sure we wrap that right too."
- message = changelog._message_for_revert([12345], long_reason, "http://example.com/123")
- self.assertEquals(message, self._revert_message)
-
- _revert_entry_with_bug_url = '''2009-08-19 Eric Seidel <eric@webkit.org>
-
- Unreviewed, rolling out r12345.
- http://trac.webkit.org/changeset/12345
- http://example.com/123
-
- Reason
-
- * Scripts/bugzilla-tool:
-'''
-
- _revert_entry_without_bug_url = '''2009-08-19 Eric Seidel <eric@webkit.org>
-
- Unreviewed, rolling out r12345.
- http://trac.webkit.org/changeset/12345
-
- Reason
-
- * Scripts/bugzilla-tool:
-'''
-
- _multiple_revert_entry_with_bug_url = '''2009-08-19 Eric Seidel <eric@webkit.org>
-
- Unreviewed, rolling out r12345, r12346, and r12347.
- http://trac.webkit.org/changeset/12345
- http://trac.webkit.org/changeset/12346
- http://trac.webkit.org/changeset/12347
- http://example.com/123
-
- Reason
-
- * Scripts/bugzilla-tool:
-'''
-
- _multiple_revert_entry_without_bug_url = '''2009-08-19 Eric Seidel <eric@webkit.org>
-
- Unreviewed, rolling out r12345, r12346, and r12347.
- http://trac.webkit.org/changeset/12345
- http://trac.webkit.org/changeset/12346
- http://trac.webkit.org/changeset/12347
-
- Reason
-
- * Scripts/bugzilla-tool:
-'''
-
- def _assert_update_for_revert_output(self, args, expected_entry):
- changelog_contents = u"%s\n%s" % (self._new_entry_boilerplate, self._example_changelog)
- changelog_path = self._write_tmp_file_with_contents(changelog_contents.encode("utf-8"))
- changelog = ChangeLog(changelog_path)
- changelog.update_for_revert(*args)
- actual_entry = changelog.latest_entry()
- os.remove(changelog_path)
- self.assertEquals(actual_entry.contents(), expected_entry)
- self.assertEquals(actual_entry.reviewer_text(), None)
- # These checks could be removed to allow this to work on other entries:
- self.assertEquals(actual_entry.author_name(), "Eric Seidel")
- self.assertEquals(actual_entry.author_email(), "eric@webkit.org")
-
- def test_update_for_revert(self):
- self._assert_update_for_revert_output([[12345], "Reason"], self._revert_entry_without_bug_url)
- self._assert_update_for_revert_output([[12345], "Reason", "http://example.com/123"], self._revert_entry_with_bug_url)
- self._assert_update_for_revert_output([[12345, 12346, 12347], "Reason"], self._multiple_revert_entry_without_bug_url)
- self._assert_update_for_revert_output([[12345, 12346, 12347], "Reason", "http://example.com/123"], self._multiple_revert_entry_with_bug_url)
-
-
-if __name__ == '__main__':
- unittest.main()
diff --git a/Tools/Scripts/webkitpy/common/checkout/deps.py b/Tools/Scripts/webkitpy/common/checkout/deps.py
new file mode 100644
index 0000000..6b87ff1
--- /dev/null
+++ b/Tools/Scripts/webkitpy/common/checkout/deps.py
@@ -0,0 +1,61 @@
+# Copyright (C) 2011, Google Inc. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+# * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+# WebKit's Python module for parsing and modifying ChangeLog files
+
+import codecs
+import fileinput
+import os.path
+import re
+import textwrap
+
+
+class DEPS(object):
+
+ _variable_regexp = r"\s+'%s':\s+'(?P<value>\d+)'"
+
+ def __init__(self, path):
+ self._path = path
+
+ def read_variable(self, name):
+ pattern = re.compile(self._variable_regexp % name)
+ for line in fileinput.FileInput(self._path):
+ match = pattern.match(line)
+ if match:
+ return int(match.group("value"))
+
+ def write_variable(self, name, value):
+ pattern = re.compile(self._variable_regexp % name)
+ replacement_line = " '%s': '%s'" % (name, value)
+ # inplace=1 creates a backup file and re-directs stdout to the file
+ for line in fileinput.FileInput(self._path, inplace=1):
+ if pattern.match(line):
+ print replacement_line
+ continue
+ # Trailing comma suppresses printing newline
+ print line,
diff --git a/Tools/Scripts/webkitpy/common/checkout/scm.py b/Tools/Scripts/webkitpy/common/checkout/scm.py
index 421c0dc..3fa2db5 100644
--- a/Tools/Scripts/webkitpy/common/checkout/scm.py
+++ b/Tools/Scripts/webkitpy/common/checkout/scm.py
@@ -34,10 +34,10 @@ import re
import sys
import shutil
-from webkitpy.common.system.executive import Executive, run_command, ScriptError
-from webkitpy.common.system.deprecated_logging import error, log
-import webkitpy.common.system.ospath as ospath
from webkitpy.common.memoized import memoized
+from webkitpy.common.system.deprecated_logging import error, log
+from webkitpy.common.system.executive import Executive, run_command, ScriptError
+from webkitpy.common.system import ospath
def find_checkout_root():
@@ -746,6 +746,22 @@ class Git(SCM):
def display_name(self):
return "git"
+ def prepend_svn_revision(self, diff):
+ revision = None
+ tries = 0
+ while not revision and tries < 10:
+ # If the git checkout is not tracking an SVN repo, then svn_revision_from_git_commit throws.
+ try:
+ revision = self.svn_revision_from_git_commit('HEAD~' + str(tries))
+ except:
+ return diff
+ tries += 1
+
+ if not revision:
+ return diff
+
+ return "Subversion Revision: " + str(revision) + '\n' + diff
+
def create_patch(self, git_commit=None, changed_files=None):
"""Returns a byte array (str()) representing the patch file.
Patch files are effectively binary since they may contain
@@ -753,7 +769,7 @@ class Git(SCM):
command = ['git', 'diff', '--binary', "--no-ext-diff", "--full-index", "-M", self.merge_base(git_commit), "--"]
if changed_files:
command += changed_files
- return self.run(command, decode_output=False, cwd=self.checkout_root)
+ return self.prepend_svn_revision(self.run(command, decode_output=False, cwd=self.checkout_root))
def _run_git_svn_find_rev(self, arg):
# git svn find-rev always exits 0, even when the revision or commit is not found.
diff --git a/Tools/Scripts/webkitpy/common/checkout/scm_unittest.py b/Tools/Scripts/webkitpy/common/checkout/scm_unittest.py
index 64122b4..decfae0 100644
--- a/Tools/Scripts/webkitpy/common/checkout/scm_unittest.py
+++ b/Tools/Scripts/webkitpy/common/checkout/scm_unittest.py
@@ -810,6 +810,16 @@ class GitTest(SCMTest):
run_command(['git', 'config', '--add', 'svn-remote.svn.fetch', 'trunk:remote2'])
self.assertEqual(self.tracking_scm.remote_branch_ref(), 'remote1')
+ def test_create_patch(self):
+ write_into_file_at_path('test_file_commit1', 'contents')
+ run_command(['git', 'add', 'test_file_commit1'])
+ scm = detect_scm_system(self.untracking_checkout_path)
+ scm.commit_locally_with_message('message')
+
+ patch = scm.create_patch()
+ self.assertFalse(re.search(r'Subversion Revision:', patch))
+
+
class GitSVNTest(SCMTest):
def _setup_git_checkout(self):
@@ -1126,6 +1136,7 @@ class GitSVNTest(SCMTest):
patch = scm.create_patch()
self.assertTrue(re.search(r'test_file_commit2', patch))
self.assertTrue(re.search(r'test_file_commit1', patch))
+ self.assertTrue(re.search(r'Subversion Revision: 5', patch))
def test_create_patch_with_changed_files(self):
self._one_local_commit_plus_working_copy_changes()
diff --git a/Tools/Scripts/webkitpy/common/config/committers.py b/Tools/Scripts/webkitpy/common/config/committers.py
index f7d59fe..5c571ab 100644
--- a/Tools/Scripts/webkitpy/common/config/committers.py
+++ b/Tools/Scripts/webkitpy/common/config/committers.py
@@ -91,16 +91,17 @@ committers_unable_to_review = [
Committer("Cameron McCormack", "cam@webkit.org", "heycam"),
Committer("Carlos Garcia Campos", ["cgarcia@igalia.com", "carlosgc@gnome.org", "carlosgc@webkit.org"], "KaL"),
Committer("Carol Szabo", "carol.szabo@nokia.com"),
- Committer("Chang Shu", "Chang.Shu@nokia.com"),
+ Committer("Chang Shu", ["Chang.Shu@nokia.com", "cshu@webkit.org"], "cshu"),
Committer("Chris Evans", "cevans@google.com"),
Committer("Chris Petersen", "cpetersen@apple.com", "cpetersen"),
Committer("Chris Rogers", "crogers@google.com", "crogers"),
Committer("Christian Dywan", ["christian@twotoasts.de", "christian@webkit.org"]),
Committer("Collin Jackson", "collinj@webkit.org"),
+ Committer("Daniel Cheng", "dcheng@chromium.org", "dcheng"),
Committer("David Smith", ["catfish.man@gmail.com", "dsmith@webkit.org"], "catfishman"),
Committer("Dean Jackson", "dino@apple.com", "dino"),
Committer("Diego Gonzalez", ["diegohcg@webkit.org", "diego.gonzalez@openbossa.org"], "diegohcg"),
- Committer("Dirk Pranke", "dpranke@chromium.org"),
+ Committer("Dirk Pranke", "dpranke@chromium.org", "dpranke"),
Committer("Drew Wilson", "atwilson@chromium.org", "atwilson"),
Committer("Eli Fidler", "eli@staikos.net", "QBin"),
Committer("Enrica Casucci", "enrica@apple.com"),
@@ -113,6 +114,7 @@ committers_unable_to_review = [
Committer("Feng Qian", "feng@chromium.org"),
Committer("Fumitoshi Ukai", "ukai@chromium.org", "ukai"),
Committer("Gabor Loki", "loki@webkit.org", "loki04"),
+ Committer("Gabor Rapcsanyi", ["rgabor@webkit.org", "rgabor@inf.u-szeged.hu"], "rgabor"),
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"),
@@ -121,6 +123,7 @@ committers_unable_to_review = [
Committer("Hayato Ito", "hayato@chromium.org", "hayato"),
Committer("Hin-Chung Lam", ["hclam@google.com", "hclam@chromium.org"]),
Committer("Ilya Tikhonovsky", "loislo@chromium.org", "loislo"),
+ Committer("Ivan Krsti\u0107", "ike@apple.com"),
Committer("Jakob Petsovits", ["jpetsovits@rim.com", "jpetso@gmx.at"], "jpetso"),
Committer("Jakub Wieczorek", "jwieczorek@webkit.org", "fawek"),
Committer("James Hawkins", ["jhawkins@chromium.org", "jhawkins@google.com"], "jhawkins"),
@@ -137,6 +140,7 @@ committers_unable_to_review = [
Committer("John Gregg", ["johnnyg@google.com", "johnnyg@chromium.org"], "johnnyg"),
Committer("John Knottenbelt", ["jknotten@chromium.org"], "jknotten"),
Committer("Johnny Ding", ["jnd@chromium.org", "johnnyding.webkit@gmail.com"], "johnnyding"),
+ Committer("Joone Hur", ["joone.hur@collabora.co.uk", "joone@kldp.org", "joone@webkit.org"], "joone"),
Committer("Joost de Valk", ["joost@webkit.org", "webkit-dev@joostdevalk.nl"], "Altha"),
Committer("Julie Parent", ["jparent@google.com", "jparent@chromium.org"], "jparent"),
Committer("Julien Chaffraix", ["jchaffraix@webkit.org", "julien.chaffraix@gmail.com"]),
diff --git a/Tools/Scripts/webkitpy/common/config/urls.py b/Tools/Scripts/webkitpy/common/config/urls.py
index dfa6d69..ddaef97 100644
--- a/Tools/Scripts/webkitpy/common/config/urls.py
+++ b/Tools/Scripts/webkitpy/common/config/urls.py
@@ -34,5 +34,6 @@ def view_source_url(local_path):
def view_revision_url(revision_number):
return "http://trac.webkit.org/changeset/%s" % revision_number
+chromium_lkgr_url = "http://chromium-status.appspot.com/lkgr"
contribution_guidelines = "http://webkit.org/coding/contributing.html"
diff --git a/Tools/Scripts/webkitpy/common/net/buildbot/buildbot.py b/Tools/Scripts/webkitpy/common/net/buildbot/buildbot.py
index 3cb6da5..76cd31d 100644
--- a/Tools/Scripts/webkitpy/common/net/buildbot/buildbot.py
+++ b/Tools/Scripts/webkitpy/common/net/buildbot/buildbot.py
@@ -266,10 +266,11 @@ class BuildBot(object):
# See https://bugs.webkit.org/show_bug.cgi?id=33296 and related bugs.
self.core_builder_names_regexps = [
"SnowLeopard.*Build",
- "SnowLeopard.*\(Test", # Exclude WebKit2 for now.
+ "SnowLeopard.*\(Test",
+ "SnowLeopard.*\(WebKit2 Test",
"Leopard",
- "Tiger",
"Windows.*Build",
+ "EFL",
"GTK.*32",
"GTK.*64.*Debug", # Disallow the 64-bit Release bot which is broken.
"Qt",
diff --git a/Tools/Scripts/webkitpy/common/net/buildbot/buildbot_unittest.py b/Tools/Scripts/webkitpy/common/net/buildbot/buildbot_unittest.py
index 57290d1..f158827 100644
--- a/Tools/Scripts/webkitpy/common/net/buildbot/buildbot_unittest.py
+++ b/Tools/Scripts/webkitpy/common/net/buildbot/buildbot_unittest.py
@@ -222,7 +222,6 @@ class BuildBotTest(unittest.TestCase):
# For complete testing, this list should match the list of builders at build.webkit.org:
example_builders = [
- {'name': u'Tiger Intel Release', },
{'name': u'Leopard Intel Release (Build)', },
{'name': u'Leopard Intel Release (Tests)', },
{'name': u'Leopard Intel Debug (Build)', },
@@ -256,22 +255,23 @@ class BuildBotTest(unittest.TestCase):
name_regexps = [
"SnowLeopard.*Build",
"SnowLeopard.*\(Test",
+ "SnowLeopard.*\(WebKit2 Test",
"Leopard",
- "Tiger",
"Windows.*Build",
+ "EFL",
"GTK.*32",
"GTK.*64.*Debug", # Disallow the 64-bit Release bot which is broken.
"Qt",
"Chromium.*Release$",
]
expected_builders = [
- {'name': u'Tiger Intel Release', },
{'name': u'Leopard Intel Release (Build)', },
{'name': u'Leopard Intel Release (Tests)', },
{'name': u'Leopard Intel Debug (Build)', },
{'name': u'Leopard Intel Debug (Tests)', },
{'name': u'SnowLeopard Intel Release (Build)', },
{'name': u'SnowLeopard Intel Release (Tests)', },
+ {'name': u'SnowLeopard Intel Release (WebKit2 Tests)', },
{'name': u'Windows Release (Build)', },
{'name': u'Windows Debug (Build)', },
{'name': u'GTK Linux 32-bit Release', },
diff --git a/Tools/Scripts/webkitpy/common/net/irc/ircbot.py b/Tools/Scripts/webkitpy/common/net/irc/ircbot.py
index f742867..061a43c 100644
--- a/Tools/Scripts/webkitpy/common/net/irc/ircbot.py
+++ b/Tools/Scripts/webkitpy/common/net/irc/ircbot.py
@@ -26,7 +26,7 @@
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-import webkitpy.common.config.irc as config_irc
+from webkitpy.common.config import irc as config_irc
from webkitpy.common.thread.messagepump import MessagePump, MessagePumpDelegate
from webkitpy.thirdparty.autoinstalled.irc import ircbot
diff --git a/Tools/Scripts/webkitpy/common/net/layouttestresults.py b/Tools/Scripts/webkitpy/common/net/layouttestresults.py
index 28caad4..249ecc9 100644
--- a/Tools/Scripts/webkitpy/common/net/layouttestresults.py
+++ b/Tools/Scripts/webkitpy/common/net/layouttestresults.py
@@ -51,11 +51,13 @@ class LayoutTestResults(object):
timeout_key = u'Tests that timed out:'
crash_key = u'Tests that caused the DumpRenderTree tool to crash:'
missing_key = u'Tests that had no expected results (probably new):'
+ webprocess_crash_key = u'Tests that caused the Web process to crash:'
expected_keys = [
stderr_key,
fail_key,
crash_key,
+ webprocess_crash_key,
timeout_key,
missing_key,
]
@@ -87,6 +89,8 @@ class LayoutTestResults(object):
return cls._failures_from_fail_row(row)
if table_title == cls.crash_key:
return [test_failures.FailureCrash()]
+ if table_title == cls.webprocess_crash_key:
+ return [test_failures.FailureCrash()]
if table_title == cls.timeout_key:
return [test_failures.FailureTimeout()]
if table_title == cls.missing_key:
diff --git a/Tools/Scripts/webkitpy/common/net/testoutput.py b/Tools/Scripts/webkitpy/common/net/testoutput.py
new file mode 100644
index 0000000..37c1445
--- /dev/null
+++ b/Tools/Scripts/webkitpy/common/net/testoutput.py
@@ -0,0 +1,179 @@
+#!/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:
+#
+# 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 AND ITS CONTRIBUTORS "AS IS" AND ANY
+# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+import os
+import re
+
+
+class NaiveImageDiffer(object):
+ def same_image(self, img1, img2):
+ return img1 == img2
+
+
+class TestOutput(object):
+ """Represents the output that a single layout test generates when it is run
+ on a particular platform.
+ Note that this is the raw output that is produced when the layout test is
+ run, not the results of the subsequent comparison between that output and
+ the expected output."""
+ def __init__(self, platform, output_type, files):
+ self._output_type = output_type
+ self._files = files
+ file = files[0] # Pick some file to do test name calculation.
+ self._name = self._extract_test_name(file.name())
+ self._is_actual = '-actual.' in file.name()
+
+ self._platform = platform or self._extract_platform(file.name())
+
+ def _extract_platform(self, filename):
+ """Calculates the platform from the name of the file if it isn't known already"""
+ path = re.split(os.path.sep, filename)
+ if 'platform' in path:
+ return path[path.index('platform') + 1]
+ return None
+
+ def _extract_test_name(self, filename):
+ path = re.split(os.path.sep, filename)
+ if 'LayoutTests' in path:
+ path = path[1 + path.index('LayoutTests'):]
+ if 'layout-test-results' in path:
+ path = path[1 + path.index('layout-test-results'):]
+ if 'platform' in path:
+ path = path[2 + path.index('platform'):]
+
+ filename = path[-1]
+ filename = re.sub('-expected\..*$', '', filename)
+ filename = re.sub('-actual\..*$', '', filename)
+ path[-1] = filename
+ return os.path.sep.join(path)
+
+ def save_to(self, path):
+ """Have the files in this TestOutput write themselves to the disk at the specified location."""
+ for file in self._files:
+ file.save_to(path)
+
+ def is_actual(self):
+ """Is this output the actual output of a test? (As opposed to expected output.)"""
+ return self._is_actual
+
+ def name(self):
+ """The name of this test (doesn't include extension)"""
+ return self._name
+
+ def __eq__(self, other):
+ return (other != None and
+ self.name() == other.name() and
+ self.type() == other.type() and
+ self.platform() == other.platform() and
+ self.is_actual() == other.is_actual() and
+ self.same_content(other))
+
+ def __hash__(self):
+ return hash(str(self.name()) + str(self.type()) + str(self.platform()))
+
+ def is_new_baseline_for(self, other):
+ return (self.name() == other.name() and
+ self.type() == other.type() and
+ self.platform() == other.platform() and
+ self.is_actual() and
+ (not other.is_actual()))
+
+ def __str__(self):
+ actual_str = '[A] ' if self.is_actual() else ''
+ return "TestOutput[%s/%s] %s%s" % (self._platform, self._output_type, actual_str, self.name())
+
+ def type(self):
+ return self._output_type
+
+ def platform(self):
+ return self._platform
+
+ def _path_to_platform(self):
+ """Returns the path that tests for this platform are stored in."""
+ if self._platform is None:
+ return ""
+ else:
+ return os.path.join("self._platform", self._platform)
+
+ def _save_expected_result(self, file, path):
+ path = os.path.join(path, self._path_to_platform())
+ extension = os.path.splitext(file.name())[1]
+ filename = self.name() + '-expected' + extension
+ file.save_to(path, filename)
+
+ def save_expected_results(self, path_to_layout_tests):
+ """Save the files of this TestOutput to the appropriate directory
+ inside the LayoutTests directory. Typically this means that these files
+ will be saved in "LayoutTests/platform/<platform>/, or simply
+ LayoutTests if the platform is None."""
+ for file in self._files:
+ self._save_expected_result(file, path_to_layout_tests)
+
+ def delete(self):
+ """Deletes the files that comprise this TestOutput from disk. This
+ fails if the files are virtual files (eg: the files may reside inside a
+ remote zip file)."""
+ for file in self._files:
+ file.delete()
+
+
+class TextTestOutput(TestOutput):
+ """Represents a text output of a single test on a single platform"""
+ def __init__(self, platform, text_file):
+ self._text_file = text_file
+ TestOutput.__init__(self, platform, 'text', [text_file])
+
+ def same_content(self, other):
+ return self._text_file.contents() == other._text_file.contents()
+
+ def retarget(self, platform):
+ return TextTestOutput(platform, self._text_file)
+
+
+class ImageTestOutput(TestOutput):
+ image_differ = NaiveImageDiffer()
+ """Represents an image output of a single test on a single platform"""
+ def __init__(self, platform, image_file, checksum_file):
+ self._checksum_file = checksum_file
+ self._image_file = image_file
+ files = filter(bool, [self._checksum_file, self._image_file])
+ TestOutput.__init__(self, platform, 'image', files)
+
+ def has_checksum(self):
+ return self._checksum_file is not None
+
+ def same_content(self, other):
+ # FIXME This should not assume that checksums are up to date.
+ if self.has_checksum() and other.has_checksum():
+ return self._checksum_file.contents() == other._checksum_file.contents()
+ else:
+ self_contents = self._image_file.contents()
+ other_contents = other._image_file.contents()
+ return ImageTestOutput.image_differ.same_image(self_contents, other_contents)
+
+ def retarget(self, platform):
+ return ImageTestOutput(platform, self._image_file, self._checksum_file)
+
+ def checksum(self):
+ return self._checksum_file.contents()
diff --git a/Tools/Scripts/webkitpy/common/net/testoutput_unittest.py b/Tools/Scripts/webkitpy/common/net/testoutput_unittest.py
new file mode 100644
index 0000000..ad38ca6
--- /dev/null
+++ b/Tools/Scripts/webkitpy/common/net/testoutput_unittest.py
@@ -0,0 +1,133 @@
+#!/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:
+#
+# 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 AND ITS CONTRIBUTORS "AS IS" AND ANY
+# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+import re
+import testoutput
+import unittest
+
+
+class FakeFile(object):
+ def __init__(self, filename, contents="fake contents"):
+ self._filename = filename
+ self._contents = contents
+
+ def name(self):
+ return self._filename
+
+ def contents(self):
+ return self._contents
+
+
+class FakeTestOutput(testoutput.TestOutput):
+ def __init__(self, platform, output_type, contents, is_expected=False):
+ self._output_type = output_type
+ self._contents = contents
+ self._is_expected = is_expected
+ actual = 'actual'
+ if is_expected:
+ actual = 'expected'
+ test_name = 'anonymous-test-%s.txt' % actual
+ file = FakeFile(test_name, contents)
+ super(FakeTestOutput, self).__init__(platform, output_type, [file])
+
+ def contents(self):
+ return self._contents
+
+ def retarget(self, platform):
+ return FakeTestOutput(platform, self._output_type, self._contents, self._is_expected)
+
+
+class TestOutputTest(unittest.TestCase):
+ def _check_name(self, filename, expected_test_name):
+ r = testoutput.TextTestOutput(None, FakeFile(filename))
+ self.assertEquals(expected_test_name, r.name())
+
+ def _check_platform(self, filename, expected_platform):
+ r = testoutput.TextTestOutput(None, FakeFile(filename))
+ self.assertEquals(expected_platform, r.platform())
+
+ def test_extracts_name_correctly(self):
+ self._check_name('LayoutTests/fast/dom/a-expected.txt', 'fast/dom/a')
+ self._check_name('LayoutTests/fast/dom/a-actual.txt', 'fast/dom/a')
+ self._check_name('LayoutTests/platform/win/fast/a-expected.txt', 'fast/a')
+ self._check_name('LayoutTests/platform/win/fast/a-expected.checksum', 'fast/a')
+ self._check_name('fast/dom/test-expected.txt', 'fast/dom/test')
+ self._check_name('layout-test-results/fast/a-actual.checksum', 'fast/a')
+
+ def test_extracts_platform_correctly(self):
+ self._check_platform('LayoutTests/platform/win/fast/a-expected.txt', 'win')
+ self._check_platform('platform/win/fast/a-expected.txt', 'win')
+ self._check_platform('platform/mac/fast/a-expected.txt', 'mac')
+ self._check_platform('fast/a-expected.txt', None)
+
+ def test_outputs_from_an_actual_file_are_marked_as_such(self):
+ r = testoutput.TextTestOutput(None, FakeFile('test-actual.txt'))
+ self.assertTrue(r.is_actual())
+
+ def test_outputs_from_an_expected_file_are_not_actual(self):
+ r = testoutput.TextTestOutput(None, FakeFile('test-expected.txt'))
+ self.assertFalse(r.is_actual())
+
+ def test_is_new_baseline_for(self):
+ expected = testoutput.TextTestOutput('mac', FakeFile('test-expected.txt'))
+ actual = testoutput.TextTestOutput('mac', FakeFile('test-actual.txt'))
+ self.assertTrue(actual.is_new_baseline_for(expected))
+ self.assertFalse(expected.is_new_baseline_for(actual))
+
+ def test__eq__(self):
+ r1 = testoutput.TextTestOutput('mac', FakeFile('test-expected.txt', 'contents'))
+ r2 = testoutput.TextTestOutput('mac', FakeFile('test-expected.txt', 'contents'))
+ r3 = testoutput.TextTestOutput('win', FakeFile('test-expected.txt', 'contents'))
+
+ self.assertEquals(r1, r2)
+ self.assertEquals(r1, r2.retarget('mac'))
+ self.assertNotEquals(r1, r2.retarget('win'))
+
+ def test__hash__(self):
+ r1 = testoutput.TextTestOutput('mac', FakeFile('test-expected.txt', 'contents'))
+ r2 = testoutput.TextTestOutput('mac', FakeFile('test-expected.txt', 'contents'))
+ r3 = testoutput.TextTestOutput(None, FakeFile('test-expected.txt', None))
+
+ x = set([r1, r2])
+ self.assertEquals(1, len(set([r1, r2])))
+ self.assertEquals(2, len(set([r1, r2, r3])))
+
+ def test_image_diff_is_invoked_for_image_outputs_without_checksum(self):
+ r1 = testoutput.ImageTestOutput('mac', FakeFile('test-expected.png', 'asdf'), FakeFile('test-expected.checksum', 'check'))
+ r2 = testoutput.ImageTestOutput('mac', FakeFile('test-expected.png', 'asdf'), None)
+
+ # Default behaviour is to just compare on image contents.
+ self.assertTrue(r1.same_content(r2))
+
+ class AllImagesAreDifferent(object):
+ def same_image(self, image1, image2):
+ return False
+
+ # But we can install other image differs.
+ testoutput.ImageTestOutput.image_differ = AllImagesAreDifferent()
+
+ self.assertFalse(r1.same_content(r2))
+
+if __name__ == "__main__":
+ unittest.main()
diff --git a/Tools/Scripts/webkitpy/common/net/testoutputset.py b/Tools/Scripts/webkitpy/common/net/testoutputset.py
new file mode 100644
index 0000000..4074686
--- /dev/null
+++ b/Tools/Scripts/webkitpy/common/net/testoutputset.py
@@ -0,0 +1,130 @@
+#!/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:
+#
+# 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 AND ITS CONTRIBUTORS "AS IS" AND ANY
+# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+from webkitpy.common.system.directoryfileset import DirectoryFileSet
+from webkitpy.common.system.zipfileset import ZipFileSet
+import re
+import testoutput
+import urllib
+
+
+class TestOutputSet(object):
+ def __init__(self, name, platform, zip_file, **kwargs):
+ self._name = name
+ self._platform = platform
+ self._zip_file = zip_file
+ self._include_expected = kwargs.get('include_expected', True)
+
+ @classmethod
+ def from_zip_url(cls, platform, zip_path):
+ return TestOutputSet('local zip %s builder' % platform, platform, ZipFileSet(zip_path))
+
+ @classmethod
+ def from_zip(cls, platform, zip):
+ return TestOutputSet('local zip %s builder' % platform, platform, zip)
+
+ @classmethod
+ def from_zip_map(cls, zip_map):
+ output_sets = []
+ for k, v in zip_map.items():
+ output_sets.append(TestOutputSet.from_zip(k, v))
+ return AggregateTestOutputSet(output_sets)
+
+ @classmethod
+ def from_path(self, path, platform=None):
+ return TestOutputSet('local %s builder' % platform, platform, DirectoryFileSet(path))
+
+ def name(self):
+ return self._name
+
+ def set_platform(self, platform):
+ self._platform = platform
+
+ def files(self):
+ return [self._zip_file.open(filename) for filename in self._zip_file.namelist()]
+
+ def _extract_output_files(self, name, exact_match):
+ name_matcher = re.compile(name)
+ actual_matcher = re.compile(r'-actual\.')
+ expected_matcher = re.compile(r'-expected\.')
+
+ checksum_files = []
+ text_files = []
+ image_files = []
+ for output_file in self.files():
+ name_match = name_matcher.search(output_file.name())
+ actual_match = actual_matcher.search(output_file.name())
+ expected_match = expected_matcher.search(output_file.name())
+ if not (name_match and (actual_match or (self._include_expected and expected_match))):
+ continue
+ if output_file.name().endswith('.checksum'):
+ checksum_files.append(output_file)
+ elif output_file.name().endswith('.txt'):
+ text_files.append(output_file)
+ elif output_file.name().endswith('.png'):
+ image_files.append(output_file)
+
+ return (checksum_files, text_files, image_files)
+
+ def _extract_file_with_name(self, name, files):
+ for file in files:
+ if file.name() == name:
+ return file
+ return None
+
+ def _make_output_from_image(self, image_file, checksum_files):
+ checksum_file_name = re.sub('\.png', '.checksum', image_file.name())
+ checksum_file = self._extract_file_with_name(checksum_file_name, checksum_files)
+ return testoutput.ImageTestOutput(self._platform, image_file, checksum_file)
+
+ def outputs_for(self, name, **kwargs):
+ target_type = kwargs.get('target_type', None)
+ exact_match = kwargs.get('exact_match', False)
+ if re.search(r'\.x?html', name):
+ name = name[:name.rindex('.')]
+
+ (checksum_files, text_files, image_files) = self._extract_output_files(name, exact_match)
+
+ outputs = [self._make_output_from_image(image_file, checksum_files) for image_file in image_files]
+
+ outputs += [testoutput.TextTestOutput(self._platform, text_file) for text_file in text_files]
+
+ if exact_match:
+ outputs = filter(lambda output: output.name() == name, outputs)
+
+ outputs = filter(lambda r: target_type in [None, r.type()], outputs)
+
+ return outputs
+
+
+class AggregateTestOutputSet(object):
+ """Set of test outputs from a list of builders"""
+ def __init__(self, builders):
+ self._builders = builders
+
+ def outputs_for(self, name, **kwargs):
+ return sum([builder.outputs_for(name, **kwargs) for builder in self._builders], [])
+
+ def builders(self):
+ return self._builders
diff --git a/Tools/Scripts/webkitpy/common/net/testoutputset_unittest.py b/Tools/Scripts/webkitpy/common/net/testoutputset_unittest.py
new file mode 100644
index 0000000..a70a539
--- /dev/null
+++ b/Tools/Scripts/webkitpy/common/net/testoutputset_unittest.py
@@ -0,0 +1,125 @@
+#!/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:
+#
+# 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 AND ITS CONTRIBUTORS "AS IS" AND ANY
+# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+from webkitpy.common.system.zip_mock import MockZip
+import testoutputset
+import unittest
+
+
+class TestOutputSetTest(unittest.TestCase):
+ def _outputset_with_zip(self, zip, **kwargs):
+ return testoutputset.TestOutputSet('<fake-outputset>', '<fake-platform>', zip, **kwargs)
+
+ def test_text_files_get_interpreted_as_text_outputs(self):
+ zip = MockZip()
+ zip.insert('fast/dom/some-test-actual.txt', 'actual outputs')
+ b = self._outputset_with_zip(zip)
+ self.assertEquals(1, len(b.outputs_for('fast/dom/some-test')))
+ self.assertEquals('fast/dom/some-test', b.outputs_for('fast/dom/some-test.html')[0].name())
+
+ def test_image_and_checksum_files_get_interpreted_as_a_single_image_output(self):
+ zip = MockZip()
+ zip.insert('fast/dom/some-test-actual.checksum', 'abc123')
+ zip.insert('fast/dom/some-test-actual.png', '<image data>')
+ b = self._outputset_with_zip(zip)
+ outputs = b.outputs_for('fast/dom/some-test')
+ self.assertEquals(1, len(outputs))
+ output = outputs[0]
+ self.assertEquals('image', output.type())
+ self.assertEquals('abc123', output.checksum())
+
+ def test_multiple_image_outputs_are_detected(self):
+ zip = MockZip()
+ zip.insert('platform/win/fast/dom/some-test-actual.checksum', 'checksum1')
+ zip.insert('platform/win/fast/dom/some-test-actual.png', '<image data 1>')
+ zip.insert('platform/mac/fast/dom/some-test-actual.checksum', 'checksum2')
+ zip.insert('platform/mac/fast/dom/some-test-actual.png', '<image data 2>')
+ b = self._outputset_with_zip(zip)
+ outputs = b.outputs_for('fast/dom/some-test')
+ self.assertEquals(2, len(outputs))
+ self.assertFalse(outputs[0].same_content(outputs[1]))
+
+ def test_aggregate_output_set_correctly_retrieves_tests_from_multiple_output_sets(self):
+ outputset1_zip = MockZip()
+ outputset1_zip.insert('fast/dom/test-actual.txt', 'linux text output')
+ outputset1 = testoutputset.TestOutputSet('linux-outputset', 'linux', outputset1_zip)
+ outputset2_zip = MockZip()
+ outputset2_zip.insert('fast/dom/test-actual.txt', 'windows text output')
+ outputset2 = testoutputset.TestOutputSet('win-outputset', 'win', outputset2_zip)
+
+ b = testoutputset.AggregateTestOutputSet([outputset1, outputset2])
+ self.assertEquals(2, len(b.outputs_for('fast/dom/test')))
+
+ def test_can_infer_platform_from_path_if_none_provided(self):
+ zip = MockZip()
+ zip.insert('platform/win/some-test-expected.png', '<image data>')
+ zip.insert('platform/win/some-test-expected.checksum', 'abc123')
+ b = testoutputset.TestOutputSet('local LayoutTests outputset', None, zip)
+
+ outputs = b.outputs_for('some-test')
+ self.assertEquals(1, len(outputs))
+ self.assertEquals('win', outputs[0].platform())
+
+ def test_test_extension_is_ignored(self):
+ zip = MockZip()
+ zip.insert('test/test-a-actual.txt', 'actual outputs')
+ b = self._outputset_with_zip(zip)
+ outputs = b.outputs_for('test/test-a.html')
+ self.assertEquals(1, len(outputs))
+ self.assertEquals('test/test-a', outputs[0].name())
+
+ def test_existing_outputs_are_marked_as_such(self):
+ zip = MockZip()
+ zip.insert('test/test-a-expected.txt', 'expected outputs')
+ b = self._outputset_with_zip(zip)
+ outputs = b.outputs_for('test/test-a.html')
+ self.assertEquals(1, len(outputs))
+ self.assertFalse(outputs[0].is_actual())
+
+ def test_only_returns_outputs_of_specified_type(self):
+ zip = MockZip()
+ zip.insert('test/test-a-expected.txt', 'expected outputs')
+ zip.insert('test/test-a-expected.checksum', 'expected outputs')
+ zip.insert('test/test-a-expected.png', 'expected outputs')
+ b = self._outputset_with_zip(zip)
+
+ outputs = b.outputs_for('test/test-a.html')
+ text_outputs = b.outputs_for('test/test-a.html', target_type='text')
+ image_outputs = b.outputs_for('test/test-a.html', target_type='image')
+
+ self.assertEquals(2, len(outputs))
+ self.assertEquals(1, len(text_outputs))
+ self.assertEquals(1, len(image_outputs))
+ self.assertEquals('text', text_outputs[0].type())
+ self.assertEquals('image', image_outputs[0].type())
+
+ def test_exclude_expected_outputs_works(self):
+ zip = MockZip()
+ zip.insert('test-expected.txt', 'expected outputs stored on server for some reason')
+ b = self._outputset_with_zip(zip, include_expected=False)
+ outputs = b.outputs_for('test', target_type=None)
+ self.assertEquals(0, len(outputs))
+
+if __name__ == "__main__":
+ unittest.main()
diff --git a/Tools/Scripts/webkitpy/common/system/directoryfileset.py b/Tools/Scripts/webkitpy/common/system/directoryfileset.py
index 11acaf4..a5cab0e 100644
--- a/Tools/Scripts/webkitpy/common/system/directoryfileset.py
+++ b/Tools/Scripts/webkitpy/common/system/directoryfileset.py
@@ -21,14 +21,8 @@
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-from __future__ import with_statement
-
-import os
-import shutil
-
from webkitpy.common.system.fileset import FileSetFileHandle
from webkitpy.common.system.filesystem import FileSystem
-import webkitpy.common.system.ospath as ospath
class DirectoryFileSet(object):
@@ -36,8 +30,8 @@ class DirectoryFileSet(object):
def __init__(self, path, filesystem=None):
self._path = path
self._filesystem = filesystem or FileSystem()
- if not self._path.endswith(os.path.sep):
- self._path += os.path.sep
+ if not self._path.endswith(self._filesystem.sep):
+ self._path += self._filesystem.sep
def _full_path(self, filename):
assert self._is_under(self._path, filename)
@@ -52,7 +46,7 @@ class DirectoryFileSet(object):
return self._filesystem.files_under(self._path)
def _is_under(self, dir, filename):
- return bool(ospath.relpath(self._filesystem.join(dir, filename), dir))
+ return bool(self._filesystem.relpath(self._filesystem.join(dir, filename), dir))
def open(self, filename):
return FileSetFileHandle(self, filename, self._filesystem)
@@ -69,7 +63,7 @@ class DirectoryFileSet(object):
dest = self._filesystem.join(path, filename)
# As filename may have slashes in it, we must ensure that the same
# directory hierarchy exists at the output path.
- self._filesystem.maybe_make_directory(os.path.split(dest)[0])
+ self._filesystem.maybe_make_directory(self._filesystem.dirname(dest))
self._filesystem.copyfile(src, dest)
def delete(self, filename):
diff --git a/Tools/Scripts/webkitpy/common/system/fileset.py b/Tools/Scripts/webkitpy/common/system/fileset.py
index 22f7c4d..598c1c5 100644
--- a/Tools/Scripts/webkitpy/common/system/fileset.py
+++ b/Tools/Scripts/webkitpy/common/system/fileset.py
@@ -22,7 +22,6 @@
# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
from __future__ import with_statement
-import os
from webkitpy.common.system.filesystem import FileSystem
@@ -38,6 +37,9 @@ class FileSetFileHandle(object):
def __str__(self):
return "%s:%s" % (self._fileset, self._filename)
+ def close(self):
+ pass
+
def contents(self):
if self._contents is None:
self._contents = self._fileset.read(self._filename)
@@ -61,4 +63,4 @@ class FileSetFileHandle(object):
return self._filename
def splitext(self):
- return os.path.splitext(self.name())
+ return self._filesystem.splitext(self.name())
diff --git a/Tools/Scripts/webkitpy/common/system/filesystem.py b/Tools/Scripts/webkitpy/common/system/filesystem.py
index 05513a9..b876807 100644
--- a/Tools/Scripts/webkitpy/common/system/filesystem.py
+++ b/Tools/Scripts/webkitpy/common/system/filesystem.py
@@ -39,13 +39,20 @@ import shutil
import tempfile
import time
+from webkitpy.common.system import ospath
+
class FileSystem(object):
"""FileSystem interface for webkitpy.
Unless otherwise noted, all paths are allowed to be either absolute
or relative."""
def __init__(self):
- self.sep = os.sep
+ self._sep = os.sep
+
+ def _get_sep(self):
+ return self._sep
+
+ sep = property(_get_sep, doc="pathname separator")
def abspath(self, path):
return os.path.abspath(path)
@@ -165,8 +172,8 @@ class FileSystem(object):
if e.errno != errno.EEXIST:
raise
- def move(self, src, dest):
- shutil.move(src, dest)
+ def move(self, source, destination):
+ shutil.move(source, destination)
def mtime(self, path):
return os.stat(path).st_mtime
@@ -200,6 +207,9 @@ class FileSystem(object):
with codecs.open(path, 'r', 'utf8') as f:
return f.read()
+ def relpath(self, path, start='.'):
+ return ospath.relpath(path, start)
+
class _WindowsError(exceptions.OSError):
"""Fake exception for Linux and Mac."""
pass
diff --git a/Tools/Scripts/webkitpy/common/system/filesystem_mock.py b/Tools/Scripts/webkitpy/common/system/filesystem_mock.py
index 0004944..aa79a8c 100644
--- a/Tools/Scripts/webkitpy/common/system/filesystem_mock.py
+++ b/Tools/Scripts/webkitpy/common/system/filesystem_mock.py
@@ -28,9 +28,11 @@
import errno
import os
-import path
import re
+from webkitpy.common.system import path
+from webkitpy.common.system import ospath
+
class MockFileSystem(object):
def __init__(self, files=None):
@@ -44,17 +46,23 @@ class MockFileSystem(object):
"""
self.files = files or {}
self.written_files = {}
- self.sep = '/'
+ self._sep = '/'
self.current_tmpno = 0
+ def _get_sep(self):
+ return self._sep
+
+ sep = property(_get_sep, doc="pathname separator")
+
def _raise_not_found(self, path):
raise IOError(errno.ENOENT, path, os.strerror(errno.ENOENT))
def _split(self, path):
- idx = path.rfind('/')
- return (path[0:idx], path[idx + 1:])
+ return path.rsplit(self.sep, 1)
def abspath(self, path):
+ if path.endswith(self.sep):
+ return path[:-1]
return path
def basename(self, path):
@@ -69,6 +77,7 @@ class MockFileSystem(object):
raise IOError(errno.EISDIR, destination, os.strerror(errno.ISDIR))
self.files[destination] = self.files[source]
+ self.written_files[destination] = self.files[source]
def dirname(self, path):
return self._split(path)[0]
@@ -90,10 +99,10 @@ class MockFileSystem(object):
if self.basename(path) in dirs_to_skip:
return []
- if not path.endswith('/'):
- path += '/'
+ if not path.endswith(self.sep):
+ path += self.sep
- dir_substrings = ['/' + d + '/' for d in dirs_to_skip]
+ dir_substrings = [self.sep + d + self.sep for d in dirs_to_skip]
for filename in self.files:
if not filename.startswith(path):
continue
@@ -117,7 +126,7 @@ class MockFileSystem(object):
return [f for f in self.files if f == path]
def isabs(self, path):
- return path.startswith('/')
+ return path.startswith(self.sep)
def isfile(self, path):
return path in self.files and self.files[path] is not None
@@ -125,8 +134,8 @@ class MockFileSystem(object):
def isdir(self, path):
if path in self.files:
return False
- if not path.endswith('/'):
- path += '/'
+ if not path.endswith(self.sep):
+ path += self.sep
# We need to use a copy of the keys here in order to avoid switching
# to a different thread and potentially modifying the dict in
@@ -135,22 +144,24 @@ class MockFileSystem(object):
return any(f.startswith(path) for f in files)
def join(self, *comps):
- return re.sub(re.escape(os.path.sep), '/', os.path.join(*comps))
+ # FIXME: might want tests for this and/or a better comment about how
+ # it works.
+ return re.sub(re.escape(os.path.sep), self.sep, os.path.join(*comps))
def listdir(self, path):
if not self.isdir(path):
raise OSError("%s is not a directory" % path)
- if not path.endswith('/'):
- path += '/'
+ if not path.endswith(self.sep):
+ path += self.sep
dirs = []
files = []
for f in self.files:
if self.exists(f) and f.startswith(path):
remaining = f[len(path):]
- if '/' in remaining:
- dir = remaining[:remaining.index('/')]
+ if self.sep in remaining:
+ dir = remaining[:remaining.index(self.sep)]
if not dir in dirs:
dirs.append(dir)
else:
@@ -164,7 +175,7 @@ class MockFileSystem(object):
def _mktemp(self, suffix='', prefix='tmp', dir=None, **kwargs):
if dir is None:
- dir = '/__im_tmp'
+ dir = self.sep + '__im_tmp'
curno = self.current_tmpno
self.current_tmpno += 1
return self.join(dir, "%s_%u_%s" % (prefix, curno, suffix))
@@ -196,24 +207,26 @@ class MockFileSystem(object):
# FIXME: Implement such that subsequent calls to isdir() work?
pass
- def move(self, src, dst):
- if self.files[src] is None:
- self._raise_not_found(src)
- self.files[dst] = self.files[src]
- self.files[src] = None
+ def move(self, source, destination):
+ if self.files[source] is None:
+ self._raise_not_found(source)
+ self.files[destination] = self.files[source]
+ self.written_files[destination] = self.files[destination]
+ self.files[source] = None
+ self.written_files[source] = None
def normpath(self, path):
return path
- def open_binary_tempfile(self, suffix):
+ def open_binary_tempfile(self, suffix=''):
path = self._mktemp(suffix)
- return WritableFileObject(self, path), path
+ return (WritableFileObject(self, path), path)
def open_text_file_for_writing(self, path, append=False):
return WritableFileObject(self, path, append)
def read_text_file(self, path):
- return self.read_binary_file(path)
+ return self.read_binary_file(path).decode('utf-8')
def read_binary_file(self, path):
# Intentionally raises KeyError if we don't recognize the path.
@@ -221,14 +234,18 @@ class MockFileSystem(object):
self._raise_not_found(path)
return self.files[path]
+ def relpath(self, path, start='.'):
+ return ospath.relpath(path, start, self.abspath, self.sep)
+
def remove(self, path):
if self.files[path] is None:
self._raise_not_found(path)
self.files[path] = None
+ self.written_files[path] = None
def rmtree(self, path):
- if not path.endswith('/'):
- path += '/'
+ if not path.endswith(self.sep):
+ path += self.sep
for f in self.files:
if f.startswith(path):
@@ -241,7 +258,7 @@ class MockFileSystem(object):
return (path[0:idx], path[idx:])
def write_text_file(self, path, contents):
- return self.write_binary_file(path, contents)
+ return self.write_binary_file(path, contents.encode('utf-8'))
def write_binary_file(self, path, contents):
self.files[path] = contents
diff --git a/Tools/Scripts/webkitpy/common/system/filesystem_unittest.py b/Tools/Scripts/webkitpy/common/system/filesystem_unittest.py
index 267ca13..8455d72 100644
--- a/Tools/Scripts/webkitpy/common/system/filesystem_unittest.py
+++ b/Tools/Scripts/webkitpy/common/system/filesystem_unittest.py
@@ -167,6 +167,19 @@ class FileSystemTest(unittest.TestCase):
self.assertTrue(fs.remove('filename', remove_with_exception))
self.assertEquals(-1, FileSystemTest._remove_failures)
+ def test_sep(self):
+ fs = FileSystem()
+
+ self.assertEquals(fs.sep, os.sep)
+ self.assertEquals(fs.join("foo", "bar"),
+ os.path.join("foo", "bar"))
+
+ def test_sep__is_readonly(self):
+ def assign_sep():
+ fs.sep = ' '
+ fs = FileSystem()
+ self.assertRaises(AttributeError, assign_sep)
+
if __name__ == '__main__':
unittest.main()
diff --git a/Tools/Scripts/webkitpy/common/system/logutils.py b/Tools/Scripts/webkitpy/common/system/logutils.py
index cd4e60f..eef4636 100644
--- a/Tools/Scripts/webkitpy/common/system/logutils.py
+++ b/Tools/Scripts/webkitpy/common/system/logutils.py
@@ -83,7 +83,7 @@ def get_logger(path):
Sample usage:
- import webkitpy.common.system.logutils as logutils
+ from webkitpy.common.system import logutils
_log = logutils.get_logger(__file__)
diff --git a/Tools/Scripts/webkitpy/common/system/logutils_unittest.py b/Tools/Scripts/webkitpy/common/system/logutils_unittest.py
index b77c284..f1b494d 100644
--- a/Tools/Scripts/webkitpy/common/system/logutils_unittest.py
+++ b/Tools/Scripts/webkitpy/common/system/logutils_unittest.py
@@ -28,7 +28,7 @@ import unittest
from webkitpy.common.system.logtesting import LogTesting
from webkitpy.common.system.logtesting import TestLogStream
-import webkitpy.common.system.logutils as logutils
+from webkitpy.common.system import logutils
class GetLoggerTest(unittest.TestCase):
diff --git a/Tools/Scripts/webkitpy/common/system/ospath.py b/Tools/Scripts/webkitpy/common/system/ospath.py
index aed7a3d..2504645 100644
--- a/Tools/Scripts/webkitpy/common/system/ospath.py
+++ b/Tools/Scripts/webkitpy/common/system/ospath.py
@@ -32,7 +32,7 @@ import os
#
# It should behave essentially the same as os.path.relpath(), except for
# returning None on paths not contained in abs_start_path.
-def relpath(path, start_path, os_path_abspath=None):
+def relpath(path, start_path, os_path_abspath=None, sep=None):
"""Return a path relative to the given start path, or None.
Returns None if the path is not contained in the directory start_path.
@@ -44,10 +44,12 @@ def relpath(path, start_path, os_path_abspath=None):
os_path_abspath: A replacement function for unit testing. This
function should strip trailing slashes just like
os.path.abspath(). Defaults to os.path.abspath.
+ sep: Path separator. Defaults to os.path.sep
"""
if os_path_abspath is None:
os_path_abspath = os.path.abspath
+ sep = sep or os.sep
# Since os_path_abspath() calls os.path.normpath()--
#
@@ -67,11 +69,11 @@ def relpath(path, start_path, os_path_abspath=None):
if not rel_path:
# Then the paths are the same.
pass
- elif rel_path[0] == os.sep:
+ elif rel_path[0] == sep:
# It is probably sufficient to remove just the first character
# since os.path.normpath() collapses separators, but we use
# lstrip() just to be sure.
- rel_path = rel_path.lstrip(os.sep)
+ rel_path = rel_path.lstrip(sep)
else:
# We are in the case typified by the following example:
#
diff --git a/Tools/Scripts/webkitpy/common/system/stack_utils.py b/Tools/Scripts/webkitpy/common/system/stack_utils.py
new file mode 100644
index 0000000..a343807
--- /dev/null
+++ b/Tools/Scripts/webkitpy/common/system/stack_utils.py
@@ -0,0 +1,67 @@
+# Copyright (C) 2011 Google Inc. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+# * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+"""Simple routines for logging, obtaining thread stack information."""
+
+import sys
+import traceback
+
+
+def log_thread_state(logger, name, thread_id, msg=''):
+ """Log information about the given thread state."""
+ stack = _find_thread_stack(thread_id)
+ assert(stack is not None)
+ logger("")
+ logger("%s (tid %d) %s" % (name, thread_id, msg))
+ _log_stack(logger, stack)
+ logger("")
+
+
+def _find_thread_stack(thread_id):
+ """Returns a stack object that can be used to dump a stack trace for
+ the given thread id (or None if the id is not found)."""
+ for tid, stack in sys._current_frames().items():
+ if tid == thread_id:
+ return stack
+ return None
+
+
+def _log_stack(logger, stack):
+ """Log a stack trace to the logger callback."""
+ for filename, lineno, name, line in traceback.extract_stack(stack):
+ logger('File: "%s", line %d, in %s' % (filename, lineno, name))
+ if line:
+ logger(' %s' % line.strip())
+
+
+def log_traceback(logger, tb):
+ stack = traceback.extract_tb(tb)
+ for frame_str in traceback.format_list(stack):
+ for line in frame_str.split('\n'):
+ if line:
+ logger(" %s" % line)
diff --git a/Tools/Scripts/webkitpy/common/system/stack_utils_unittest.py b/Tools/Scripts/webkitpy/common/system/stack_utils_unittest.py
new file mode 100644
index 0000000..b21319f
--- /dev/null
+++ b/Tools/Scripts/webkitpy/common/system/stack_utils_unittest.py
@@ -0,0 +1,76 @@
+# Copyright (C) 2011 Google Inc. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+# * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+import sys
+import unittest
+
+from webkitpy.common.system import outputcapture
+from webkitpy.common.system import stack_utils
+
+
+def current_thread_id():
+ thread_id, _ = sys._current_frames().items()[0]
+ return thread_id
+
+
+class Test(unittest.TestCase):
+ def test_find_thread_stack_found(self):
+ thread_id = current_thread_id()
+ found_stack = stack_utils._find_thread_stack(thread_id)
+ self.assertNotEqual(found_stack, None)
+
+ def test_find_thread_stack_not_found(self):
+ found_stack = stack_utils._find_thread_stack(0)
+ self.assertEqual(found_stack, None)
+
+ def test_log_thread_state(self):
+ msgs = []
+
+ def logger(msg):
+ msgs.append(msg)
+
+ thread_id = current_thread_id()
+ stack_utils.log_thread_state(logger, "test-thread", thread_id,
+ "is tested")
+ self.assertTrue(msgs)
+
+ def test_log_traceback(self):
+ msgs = []
+
+ def logger(msg):
+ msgs.append(msg)
+
+ try:
+ raise ValueError
+ except:
+ stack_utils.log_traceback(logger, sys.exc_info()[2])
+ self.assertTrue(msgs)
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/Tools/Scripts/webkitpy/layout_tests/layout_package/test_output.py b/Tools/Scripts/webkitpy/common/system/urlfetcher.py
index e809be6..2d9e5ec 100644
--- a/Tools/Scripts/webkitpy/layout_tests/layout_package/test_output.py
+++ b/Tools/Scripts/webkitpy/common/system/urlfetcher.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2010 Google Inc. All rights reserved.
+# Copyright (C) 2011 Google Inc. All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
@@ -26,31 +26,30 @@
# (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 module for fetching URLs."""
-class TestOutput(object):
- """Groups information about a test output for easy passing of data.
+import urllib
- This is used not only for a actual test output, but also for grouping
- expected test output.
- """
- def __init__(self, text, image, image_hash,
- crash=None, test_time=None, timeout=None, error=None):
- """Initializes a TestOutput object.
+class UrlFetcher(object):
+ """Class with restricted interface to fetch URLs (makes testing easier)"""
+ def __init__(self, filesystem):
+ self._filesystem = filesystem
- Args:
- text: a text output
- image: an image output
- image_hash: a string containing the checksum of the image
- crash: a boolean indicating whether the driver crashed on the test
- test_time: a time which the test has taken
- timeout: a boolean indicating whehter the test timed out
- error: any unexpected or additional (or error) text output
+ def fetch(self, url):
+ """Fetches the contents of the URL as a string."""
+ file_object = urllib.urlopen(url)
+ content = file_object.read()
+ file_object.close()
+ return content
+
+ def fetch_into_file(self, url):
+ """Fetches the contents of the URL into a temporary file and return the filename.
+
+ This is the equivalent of urllib.retrieve() except that we don't return any headers.
"""
- self.text = text
- self.image = image
- self.image_hash = image_hash
- self.crash = crash
- self.test_time = test_time
- self.timeout = timeout
- self.error = error
+ file_object, filename = self._filesystem.open_binary_tempfile('-fetched')
+ contents = self.fetch(url)
+ file_object.write(contents)
+ file_object.close()
+ return filename
diff --git a/Tools/Scripts/webkitpy/common/system/urlfetcher_mock.py b/Tools/Scripts/webkitpy/common/system/urlfetcher_mock.py
new file mode 100644
index 0000000..e8a7532
--- /dev/null
+++ b/Tools/Scripts/webkitpy/common/system/urlfetcher_mock.py
@@ -0,0 +1,46 @@
+# Copyright (C) 2011 Google Inc. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+# * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+def make_fetcher_cls(urls):
+ """UrlFetcher factory routine that simulates network access
+ using a dict of URLs -> contents."""
+ class MockFetcher(object):
+ def __init__(self, filesystem):
+ self._filesystem = filesystem
+
+ def fetch(self, url):
+ return urls[url]
+
+ def fetch_into_file(self, url):
+ f, fn = self._filesystem.open_binary_tempfile('mockfetcher')
+ f.write(self.fetch(url))
+ f.close()
+ return fn
+
+ return MockFetcher
diff --git a/Tools/Scripts/webkitpy/common/system/zip_mock.py b/Tools/Scripts/webkitpy/common/system/zip_mock.py
new file mode 100644
index 0000000..dcfaba7
--- /dev/null
+++ b/Tools/Scripts/webkitpy/common/system/zip_mock.py
@@ -0,0 +1,55 @@
+# 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:
+#
+# 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 AND ITS CONTRIBUTORS "AS IS" AND ANY
+# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+from webkitpy.common.system.fileset import FileSetFileHandle
+from webkitpy.common.system.filesystem_mock import MockFileSystem
+
+
+class MockZip(object):
+ """A mock zip file that can have new files inserted into it."""
+ def __init__(self, filesystem=None):
+ self._filesystem = filesystem or MockFileSystem()
+ self._files = {}
+
+ def __str__(self):
+ return "MockZip"
+
+ def insert(self, filename, content):
+ self._files[filename] = content
+
+ def namelist(self):
+ return self._files.keys()
+
+ def open(self, filename):
+ return FileSetFileHandle(self, filename)
+
+ def read(self, filename):
+ return self._files[filename]
+
+ def extract(self, filename, path):
+ full_path = self._filesystem.join(path, filename)
+ contents = self.open(filename).contents()
+ self._filesystem.write_text_file(full_path, contents)
+
+ def delete(self, filename):
+ self._files[filename] = None
diff --git a/Tools/Scripts/webkitpy/common/system/zipfileset.py b/Tools/Scripts/webkitpy/common/system/zipfileset.py
index fa2b762..5cf3616 100644
--- a/Tools/Scripts/webkitpy/common/system/zipfileset.py
+++ b/Tools/Scripts/webkitpy/common/system/zipfileset.py
@@ -33,22 +33,28 @@ class ZipFileSet(object):
"""The set of files in a zip file that resides at a URL (local or remote)"""
def __init__(self, zip_url, filesystem=None, zip_factory=None):
self._zip_url = zip_url
+ self._temp_file = None
self._zip_file = None
self._filesystem = filesystem or FileSystem()
self._zip_factory = zip_factory or self._retrieve_zip_file
def _retrieve_zip_file(self, zip_url):
temp_file = NetworkTransaction().run(lambda: urllib.urlretrieve(zip_url)[0])
- return zipfile.ZipFile(temp_file)
+ return (temp_file, zipfile.ZipFile(temp_file))
def _load(self):
if self._zip_file is None:
- self._zip_file = self._zip_factory(self._zip_url)
+ self._temp_file, self._zip_file = self._zip_factory(self._zip_url)
def open(self, filename):
self._load()
return FileSetFileHandle(self, filename, self._filesystem)
+ def close(self):
+ if self._temp_file:
+ self._filesystem.remove(self._temp_file)
+ self._temp_file = None
+
def namelist(self):
self._load()
return self._zip_file.namelist()
diff --git a/Tools/Scripts/webkitpy/common/system/zipfileset_mock.py b/Tools/Scripts/webkitpy/common/system/zipfileset_mock.py
new file mode 100644
index 0000000..24ac8cb
--- /dev/null
+++ b/Tools/Scripts/webkitpy/common/system/zipfileset_mock.py
@@ -0,0 +1,51 @@
+# Copyright (C) 2011 Google Inc. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+# * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+def make_factory(ziphashes):
+ """ZipFileSet factory routine that looks up zipfiles in a dict;
+ each zipfile should also be a dict of member names -> contents."""
+ class MockZipFileSet(object):
+ def __init__(self, url):
+ self._url = url
+ self._ziphash = ziphashes[url]
+
+ def namelist(self):
+ return self._ziphash.keys()
+
+ def read(self, member):
+ return self._ziphash[member]
+
+ def close(self):
+ pass
+
+ def maker(url):
+ # We return None because there's no tempfile to delete.
+ return (None, MockZipFileSet(url))
+
+ return maker
diff --git a/Tools/Scripts/webkitpy/common/system/zipfileset_unittest.py b/Tools/Scripts/webkitpy/common/system/zipfileset_unittest.py
index a9ba5ad..6801406 100644
--- a/Tools/Scripts/webkitpy/common/system/zipfileset_unittest.py
+++ b/Tools/Scripts/webkitpy/common/system/zipfileset_unittest.py
@@ -64,13 +64,17 @@ class ZipFileSetTest(unittest.TestCase):
result = FakeZip(self._filesystem)
result.add_file('some-file', 'contents')
result.add_file('a/b/some-other-file', 'other contents')
- return result
+ return (None, result)
def test_open(self):
file = self._zip.open('a/b/some-other-file')
self.assertEquals('a/b/some-other-file', file.name())
self.assertEquals('other contents', file.contents())
+ def test_close(self):
+ zipfileset = ZipFileSet('blah', self._filesystem, self.make_fake_zip)
+ zipfileset.close()
+
def test_read(self):
self.assertEquals('contents', self._zip.read('some-file'))
diff --git a/Tools/Scripts/webkitpy/layout_tests/deduplicate_tests.py b/Tools/Scripts/webkitpy/layout_tests/deduplicate_tests.py
index 51dcac8..86649b6 100644
--- a/Tools/Scripts/webkitpy/layout_tests/deduplicate_tests.py
+++ b/Tools/Scripts/webkitpy/layout_tests/deduplicate_tests.py
@@ -36,11 +36,12 @@ import os
import subprocess
import sys
import re
-import webkitpy.common.checkout.scm as scm
-import webkitpy.common.system.executive as executive
-import webkitpy.common.system.logutils as logutils
-import webkitpy.common.system.ospath as ospath
-import webkitpy.layout_tests.port.factory as port_factory
+
+from webkitpy.common.checkout import scm
+from webkitpy.common.system import executive
+from webkitpy.common.system import logutils
+from webkitpy.common.system import ospath
+from webkitpy.layout_tests.port import factory as port_factory
_log = logutils.get_logger(__file__)
diff --git a/Tools/Scripts/webkitpy/layout_tests/layout_package/dump_render_tree_thread.py b/Tools/Scripts/webkitpy/layout_tests/layout_package/dump_render_tree_thread.py
index 050eefa..7ddd7b0 100644
--- a/Tools/Scripts/webkitpy/layout_tests/layout_package/dump_render_tree_thread.py
+++ b/Tools/Scripts/webkitpy/layout_tests/layout_package/dump_render_tree_thread.py
@@ -28,17 +28,11 @@
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-"""A Thread object for running DumpRenderTree and processing URLs from a
-shared queue.
+"""This module implements a shared-memory, thread-based version of the worker
+task in new-run-webkit-tests: it receives a list of tests from TestShellThread
+and passes them one at a time to SingleTestRunner to execute."""
-Each thread runs a separate instance of the DumpRenderTree binary and validates
-the output. When there are no more URLs to process in the shared queue, the
-thread exits.
-"""
-
-import copy
import logging
-import os
import Queue
import signal
import sys
@@ -46,199 +40,13 @@ import thread
import threading
import time
-
-from webkitpy.layout_tests.test_types import image_diff
-from webkitpy.layout_tests.test_types import test_type_base
-from webkitpy.layout_tests.test_types import text_diff
-
-import test_failures
-import test_output
-import test_results
+from webkitpy.layout_tests.layout_package.single_test_runner import SingleTestRunner
_log = logging.getLogger("webkitpy.layout_tests.layout_package."
"dump_render_tree_thread")
-def _expected_test_output(port, filename):
- """Returns an expected TestOutput object."""
- return test_output.TestOutput(port.expected_text(filename),
- port.expected_image(filename),
- port.expected_checksum(filename))
-
-def _process_output(port, options, test_input, test_types, test_args,
- test_output, worker_name):
- """Receives the output from a DumpRenderTree process, subjects it to a
- number of tests, and returns a list of failure types the test produced.
-
- Args:
- port: port-specific hooks
- options: command line options argument from optparse
- proc: an active DumpRenderTree process
- test_input: Object containing the test filename and timeout
- test_types: list of test types to subject the output to
- test_args: arguments to be passed to each test
- test_output: a TestOutput object containing the output of the test
- worker_name: worker name for logging
-
- Returns: a TestResult object
- """
- failures = []
- fs = port._filesystem
-
- if test_output.crash:
- failures.append(test_failures.FailureCrash())
- if test_output.timeout:
- failures.append(test_failures.FailureTimeout())
-
- test_name = port.relative_test_filename(test_input.filename)
- if test_output.crash:
- _log.debug("%s Stacktrace for %s:\n%s" % (worker_name, test_name,
- test_output.error))
- filename = fs.join(options.results_directory, test_name)
- filename = fs.splitext(filename)[0] + "-stack.txt"
- fs.maybe_make_directory(fs.dirname(filename))
- fs.write_text_file(filename, test_output.error)
- elif test_output.error:
- _log.debug("%s %s output stderr lines:\n%s" % (worker_name, test_name,
- test_output.error))
-
- expected_test_output = _expected_test_output(port, test_input.filename)
-
- # Check the output and save the results.
- start_time = time.time()
- time_for_diffs = {}
- for test_type in test_types:
- start_diff_time = time.time()
- new_failures = test_type.compare_output(port, test_input.filename,
- test_args, test_output,
- expected_test_output)
- # Don't add any more failures if we already have a crash, so we don't
- # double-report those tests. We do double-report for timeouts since
- # we still want to see the text and image output.
- if not test_output.crash:
- failures.extend(new_failures)
- time_for_diffs[test_type.__class__.__name__] = (
- time.time() - start_diff_time)
-
- total_time_for_all_diffs = time.time() - start_diff_time
- return test_results.TestResult(test_input.filename, failures, test_output.test_time,
- total_time_for_all_diffs, time_for_diffs)
-
-
-def _pad_timeout(timeout):
- """Returns a safe multiple of the per-test timeout value to use
- to detect hung test threads.
-
- """
- # When we're running one test per DumpRenderTree process, we can
- # enforce a hard timeout. The DumpRenderTree watchdog uses 2.5x
- # the timeout; we want to be larger than that.
- return timeout * 3
-
-
-def _milliseconds_to_seconds(msecs):
- return float(msecs) / 1000.0
-
-
-def _should_fetch_expected_checksum(options):
- return options.pixel_tests and not (options.new_baseline or options.reset_results)
-
-
-def _run_single_test(port, options, test_input, test_types, test_args, driver, worker_name):
- # FIXME: Pull this into TestShellThread._run().
-
- # The image hash is used to avoid doing an image dump if the
- # checksums match, so it should be set to a blank value if we
- # are generating a new baseline. (Otherwise, an image from a
- # previous run will be copied into the baseline."""
- if _should_fetch_expected_checksum(options):
- test_input.image_hash = port.expected_checksum(test_input.filename)
- test_output = driver.run_test(test_input)
- return _process_output(port, options, test_input, test_types, test_args,
- test_output, worker_name)
-
-
-class SingleTestThread(threading.Thread):
- """Thread wrapper for running a single test file."""
-
- def __init__(self, port, options, worker_number, worker_name,
- test_input, test_types, test_args):
- """
- Args:
- port: object implementing port-specific hooks
- options: command line argument object from optparse
- worker_number: worker number for tests
- worker_name: for logging
- test_input: Object containing the test filename and timeout
- test_types: A list of TestType objects to run the test output
- against.
- test_args: A TestArguments object to pass to each TestType.
- """
-
- threading.Thread.__init__(self)
- self._port = port
- self._options = options
- self._test_input = test_input
- self._test_types = test_types
- self._test_args = test_args
- self._driver = None
- self._worker_number = worker_number
- self._name = worker_name
-
- def run(self):
- self._covered_run()
-
- def _covered_run(self):
- # FIXME: this is a separate routine to work around a bug
- # in coverage: see http://bitbucket.org/ned/coveragepy/issue/85.
- self._driver = self._port.create_driver(self._worker_number)
- self._driver.start()
- self._test_result = _run_single_test(self._port, self._options,
- self._test_input, self._test_types,
- self._test_args, self._driver,
- self._name)
- self._driver.stop()
-
- def get_test_result(self):
- return self._test_result
-
-
-class WatchableThread(threading.Thread):
- """This class abstracts an interface used by
- run_webkit_tests.TestRunner._wait_for_threads_to_finish for thread
- management."""
- def __init__(self):
- threading.Thread.__init__(self)
- self._canceled = False
- self._exception_info = None
- self._next_timeout = None
- self._thread_id = None
-
- def cancel(self):
- """Set a flag telling this thread to quit."""
- self._canceled = True
-
- def clear_next_timeout(self):
- """Mark a flag telling this thread to stop setting timeouts."""
- self._timeout = 0
-
- def exception_info(self):
- """If run() terminated on an uncaught exception, return it here
- ((type, value, traceback) tuple).
- Returns None if run() terminated normally. Meant to be called after
- joining this thread."""
- return self._exception_info
-
- def id(self):
- """Return a thread identifier."""
- return self._thread_id
-
- def next_timeout(self):
- """Return the time the test is supposed to finish by."""
- return self._next_timeout
-
-
-class TestShellThread(WatchableThread):
+class TestShellThread(threading.Thread):
def __init__(self, port, options, worker_number, worker_name,
filename_list_queue, result_queue):
"""Initialize all the local state for this DumpRenderTree thread.
@@ -253,50 +61,51 @@ class TestShellThread(WatchableThread):
result_queue: A thread safe Queue class that will contain
serialized TestResult objects.
"""
- WatchableThread.__init__(self)
+ threading.Thread.__init__(self)
+ self._canceled = False
+ self._exception_info = None
+ self._next_timeout = None
+ self._thread_id = None
self._port = port
self._options = options
self._worker_number = worker_number
self._name = worker_name
self._filename_list_queue = filename_list_queue
self._result_queue = result_queue
+ self._current_group = None
self._filename_list = []
- self._driver = None
self._test_group_timing_stats = {}
self._test_results = []
self._num_tests = 0
self._start_time = 0
self._stop_time = 0
- self._have_http_lock = False
self._http_lock_wait_begin = 0
self._http_lock_wait_end = 0
- self._test_types = []
- for cls in self._get_test_type_classes():
- self._test_types.append(cls(self._port,
- self._options.results_directory))
- self._test_args = self._get_test_args(worker_number)
+ def cancel(self):
+ """Set a flag telling this thread to quit."""
+ self._canceled = True
- # Current group of tests we're running.
- self._current_group = None
- # Number of tests in self._current_group.
- self._num_tests_in_current_group = None
- # Time at which we started running tests from self._current_group.
- self._current_group_start_time = None
+ def clear_next_timeout(self):
+ """Mark a flag telling this thread to stop setting timeouts."""
+ self._timeout = 0
- def _get_test_args(self, worker_number):
- """Returns the tuple of arguments for tests and for DumpRenderTree."""
- test_args = test_type_base.TestArguments()
- test_args.new_baseline = self._options.new_baseline
- test_args.reset_results = self._options.reset_results
+ def exception_info(self):
+ """If run() terminated on an uncaught exception, return it here
+ ((type, value, traceback) tuple).
+ Returns None if run() terminated normally. Meant to be called after
+ joining this thread."""
+ return self._exception_info
- return test_args
+ def id(self):
+ """Return a thread identifier."""
+ return self._thread_id
- def _get_test_type_classes(self):
- classes = [text_diff.TestTextDiff]
- if self._options.pixel_tests:
- classes.append(image_diff.ImageDiff)
- return classes
+ def next_timeout(self):
+ """Return the time the test is supposed to finish by."""
+ if self._next_timeout:
+ return self._next_timeout + self._http_lock_wait_time()
+ return self._next_timeout
def get_test_group_timing_stats(self):
"""Returns a dictionary mapping test group to a tuple of
@@ -352,17 +161,6 @@ class TestShellThread(WatchableThread):
do multi-threaded debugging."""
self._run(test_runner, result_summary)
- def cancel(self):
- """Clean up http lock and set a flag telling this thread to quit."""
- self._stop_servers_with_lock()
- WatchableThread.cancel(self)
-
- def next_timeout(self):
- """Return the time the test is supposed to finish by."""
- if self._next_timeout:
- return self._next_timeout + self._http_lock_wait_time()
- return self._next_timeout
-
def _http_lock_wait_time(self):
"""Return the time what http locking takes."""
if self._http_lock_wait_begin == 0:
@@ -377,18 +175,23 @@ class TestShellThread(WatchableThread):
If test_runner is not None, then we call test_runner.UpdateSummary()
with the results of each test."""
+ single_test_runner = SingleTestRunner(self._options, self._port,
+ self._name, self._worker_number)
+
batch_size = self._options.batch_size
batch_count = 0
# Append tests we're running to the existing tests_run.txt file.
# This is created in run_webkit_tests.py:_PrepareListsAndPrintOutput.
tests_run_filename = self._port._filesystem.join(self._options.results_directory,
- "tests_run.txt")
+ "tests_run%d.txt" % self._worker_number)
tests_run_file = self._port._filesystem.open_text_file_for_writing(tests_run_filename, append=False)
+
while True:
if self._canceled:
_log.debug('Testing cancelled')
tests_run_file.close()
+ single_test_runner.cleanup()
return
if len(self._filename_list) is 0:
@@ -401,15 +204,16 @@ class TestShellThread(WatchableThread):
self._current_group, self._filename_list = \
self._filename_list_queue.get_nowait()
except Queue.Empty:
- self._stop_servers_with_lock()
- self._kill_dump_render_tree()
tests_run_file.close()
+ single_test_runner.cleanup()
return
if self._current_group == "tests_to_http_lock":
- self._start_servers_with_lock()
- elif self._have_http_lock:
- self._stop_servers_with_lock()
+ self._http_lock_wait_begin = time.time()
+ single_test_runner.start_servers_with_lock()
+ self._http_lock_wait_end = time.time()
+ elif single_test_runner.has_http_lock:
+ single_test_runner.stop_servers_with_lock()
self._num_tests_in_current_group = len(self._filename_list)
self._current_group_start_time = time.time()
@@ -419,145 +223,31 @@ class TestShellThread(WatchableThread):
# We have a url, run tests.
batch_count += 1
self._num_tests += 1
- if self._options.run_singly:
- result = self._run_test_in_another_thread(test_input)
- else:
- result = self._run_test_in_this_thread(test_input)
- filename = test_input.filename
- tests_run_file.write(filename + "\n")
+ timeout = single_test_runner.timeout(test_input)
+ result = single_test_runner.run_test(test_input, timeout)
+
+ tests_run_file.write(test_input.filename + "\n")
+ test_name = self._port.relative_test_filename(test_input.filename)
if result.failures:
# Check and kill DumpRenderTree if we need to.
- if len([1 for f in result.failures
- if f.should_kill_dump_render_tree()]):
- self._kill_dump_render_tree()
+ if any([f.should_kill_dump_render_tree() for f in result.failures]):
+ single_test_runner.kill_dump_render_tree()
# Reset the batch count since the shell just bounced.
batch_count = 0
+
# Print the error message(s).
- error_str = '\n'.join([' ' + f.message() for
- f in result.failures])
- _log.debug("%s %s failed:\n%s" % (self.getName(),
- self._port.relative_test_filename(filename),
- error_str))
+ _log.debug("%s %s failed:" % (self._name, test_name))
+ for f in result.failures:
+ _log.debug("%s %s" % (self._name, f.message()))
else:
- _log.debug("%s %s passed" % (self.getName(),
- self._port.relative_test_filename(filename)))
+ _log.debug("%s %s passed" % (self._name, test_name))
self._result_queue.put(result.dumps())
if batch_size > 0 and batch_count >= batch_size:
# Bounce the shell and reset count.
- self._kill_dump_render_tree()
+ single_test_runner.kill_dump_render_tree()
batch_count = 0
if test_runner:
test_runner.update_summary(result_summary)
-
- def _run_test_in_another_thread(self, test_input):
- """Run a test in a separate thread, enforcing a hard time limit.
-
- Since we can only detect the termination of a thread, not any internal
- state or progress, we can only run per-test timeouts when running test
- files singly.
-
- Args:
- test_input: Object containing the test filename and timeout
-
- Returns:
- A TestResult
- """
- worker = SingleTestThread(self._port,
- self._options,
- self._worker_number,
- self._name,
- test_input,
- self._test_types,
- self._test_args)
-
- worker.start()
-
- thread_timeout = _milliseconds_to_seconds(
- _pad_timeout(int(test_input.timeout)))
- thread._next_timeout = time.time() + thread_timeout
- worker.join(thread_timeout)
- if worker.isAlive():
- # If join() returned with the thread still running, the
- # DumpRenderTree is completely hung and there's nothing
- # more we can do with it. We have to kill all the
- # DumpRenderTrees to free it up. If we're running more than
- # one DumpRenderTree thread, we'll end up killing the other
- # DumpRenderTrees too, introducing spurious crashes. We accept
- # that tradeoff in order to avoid losing the rest of this
- # thread's results.
- _log.error('Test thread hung: killing all DumpRenderTrees')
- if worker._driver:
- worker._driver.stop()
-
- try:
- result = worker.get_test_result()
- except AttributeError, e:
- # This gets raised if the worker thread has already exited.
- _log.error('Cannot get results of test: %s' % test_input.filename)
- # FIXME: Seems we want a unique failure type here.
- result = test_results.TestResult(test_input.filename)
-
- return result
-
- def _run_test_in_this_thread(self, test_input):
- """Run a single test file using a shared DumpRenderTree process.
-
- Args:
- test_input: Object containing the test filename, uri and timeout
-
- Returns: a TestResult object.
- """
- self._ensure_dump_render_tree_is_running()
- thread_timeout = _milliseconds_to_seconds(
- _pad_timeout(int(test_input.timeout)))
- self._next_timeout = time.time() + thread_timeout
- test_result = _run_single_test(self._port, self._options, test_input,
- self._test_types, self._test_args,
- self._driver, self._name)
- self._test_results.append(test_result)
- return test_result
-
- def _ensure_dump_render_tree_is_running(self):
- """Start the shared DumpRenderTree, if it's not running.
-
- This is not for use when running tests singly, since those each start
- a separate DumpRenderTree in their own thread.
-
- """
- # poll() is not threadsafe and can throw OSError due to:
- # http://bugs.python.org/issue1731717
- if not self._driver or self._driver.poll() is not None:
- self._driver = self._port.create_driver(self._worker_number)
- self._driver.start()
-
- 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
-
- def _kill_dump_render_tree(self):
- """Kill the DumpRenderTree process if it's running."""
- if self._driver:
- self._driver.stop()
- self._driver = None
diff --git a/Tools/Scripts/webkitpy/layout_tests/layout_package/json_layout_results_generator.py b/Tools/Scripts/webkitpy/layout_tests/layout_package/json_layout_results_generator.py
index 3267fb7..8226ed0 100644
--- a/Tools/Scripts/webkitpy/layout_tests/layout_package/json_layout_results_generator.py
+++ b/Tools/Scripts/webkitpy/layout_tests/layout_package/json_layout_results_generator.py
@@ -55,8 +55,7 @@ class JSONLayoutResultsGenerator(json_results_generator.JSONResultsGeneratorBase
def __init__(self, port, builder_name, build_name, build_number,
results_file_base_path, builder_base_url,
test_timings, expectations, result_summary, all_tests,
- generate_incremental_results=False, test_results_server=None,
- test_type="", master_name=""):
+ test_results_server=None, test_type="", master_name=""):
"""Modifies the results.json file. Grabs it off the archive directory
if it is not found locally.
@@ -67,8 +66,7 @@ class JSONLayoutResultsGenerator(json_results_generator.JSONResultsGeneratorBase
super(JSONLayoutResultsGenerator, self).__init__(
port, builder_name, build_name, build_number, results_file_base_path,
builder_base_url, {}, port.test_repository_paths(),
- generate_incremental_results, test_results_server,
- test_type, master_name)
+ test_results_server, test_type, master_name)
self._expectations = expectations
diff --git a/Tools/Scripts/webkitpy/layout_tests/layout_package/json_results_generator.py b/Tools/Scripts/webkitpy/layout_tests/layout_package/json_results_generator.py
index 32ffd71..05662c2 100644
--- a/Tools/Scripts/webkitpy/layout_tests/layout_package/json_results_generator.py
+++ b/Tools/Scripts/webkitpy/layout_tests/layout_package/json_results_generator.py
@@ -114,13 +114,16 @@ class JSONResultsGeneratorBase(object):
URL_FOR_TEST_LIST_JSON = \
"http://%s/testfile?builder=%s&name=%s&testlistjson=1&testtype=%s"
+ # FIXME: Remove generate_incremental_results once the reference to it in
+ # http://src.chromium.org/viewvc/chrome/trunk/tools/build/scripts/slave/gtest_slave_utils.py
+ # has been removed.
def __init__(self, port, builder_name, build_name, build_number,
results_file_base_path, builder_base_url,
test_results_map, svn_repositories=None,
- generate_incremental_results=False,
test_results_server=None,
test_type="",
- master_name=""):
+ master_name="",
+ generate_incremental_results=None):
"""Modifies the results.json file. Grabs it off the archive directory
if it is not found locally.
@@ -137,8 +140,6 @@ class JSONResultsGeneratorBase(object):
svn_repositories: A (json_field_name, svn_path) pair for SVN
repositories that tests rely on. The SVN revision will be
included in the JSON with the given json_field_name.
- generate_incremental_results: If true, generate incremental json file
- from current run results.
test_results_server: server that hosts test results json.
test_type: test type string (e.g. 'layout-tests').
master_name: the name of the buildbot master.
@@ -157,7 +158,6 @@ class JSONResultsGeneratorBase(object):
self._test_results_map = test_results_map
self._test_results = test_results_map.values()
- self._generate_incremental_results = generate_incremental_results
self._svn_repositories = svn_repositories
if not self._svn_repositories:
@@ -167,39 +167,20 @@ class JSONResultsGeneratorBase(object):
self._test_type = test_type
self._master_name = master_name
- self._json = None
self._archived_results = None
def generate_json_output(self):
- """Generates the JSON output file."""
-
- # Generate the JSON output file that has full results.
- # FIXME: stop writing out the full results file once all bots use
- # incremental results.
- if not self._json:
- self._json = self.get_json()
- if self._json:
- self._generate_json_file(self._json, self._results_file_path)
-
- # Generate the JSON output file that only has incremental results.
- if self._generate_incremental_results:
- json = self.get_json(incremental=True)
- if json:
- self._generate_json_file(
- json, self._incremental_results_file_path)
-
- def get_json(self, incremental=False):
+ json = self.get_json()
+ if json:
+ self._generate_json_file(
+ json, self._incremental_results_file_path)
+
+ def get_json(self):
"""Gets the results for the results.json file."""
results_json = {}
- if not incremental:
- if self._json:
- return self._json
-
- if self._archived_results:
- results_json = self._archived_results
if not results_json:
- results_json, error = self._get_archived_json_results(incremental)
+ results_json, error = self._get_archived_json_results()
if error:
# If there was an error don't write a results.json
# file at all as it would lose all the information on the
@@ -231,7 +212,7 @@ class JSONResultsGeneratorBase(object):
all_failing_tests = self._get_failed_test_names()
all_failing_tests.update(tests.iterkeys())
for test in all_failing_tests:
- self._insert_test_time_and_result(test, tests, incremental)
+ self._insert_test_time_and_result(test, tests)
return results_json
@@ -340,52 +321,39 @@ class JSONResultsGeneratorBase(object):
return ""
return ""
- def _get_archived_json_results(self, for_incremental=False):
- """Reads old results JSON file if it exists.
- Returns (archived_results, error) tuple where error is None if results
- were successfully read.
-
- if for_incremental is True, download JSON file that only contains test
+ def _get_archived_json_results(self):
+ """Download JSON file that only contains test
name list from test-results server. This is for generating incremental
JSON so the file generated has info for tests that failed before but
pass or are skipped from current run.
+
+ Returns (archived_results, error) tuple where error is None if results
+ were successfully read.
"""
results_json = {}
old_results = None
error = None
- if self._fs.exists(self._results_file_path) and not for_incremental:
- old_results = self._fs.read_text_file(self._results_file_path)
- elif self._builder_base_url or for_incremental:
- if for_incremental:
- if not self._test_results_server:
- # starting from fresh if no test results server specified.
- return {}, None
-
- results_file_url = (self.URL_FOR_TEST_LIST_JSON %
- (urllib2.quote(self._test_results_server),
- urllib2.quote(self._builder_name),
- self.RESULTS_FILENAME,
- urllib2.quote(self._test_type)))
- else:
- # Check if we have the archived JSON file on the buildbot
- # server.
- results_file_url = (self._builder_base_url +
- self._build_name + "/" + self.RESULTS_FILENAME)
- _log.error("Local results.json file does not exist. Grabbing "
- "it off the archive at " + results_file_url)
+ if not self._test_results_server:
+ return {}, None
- try:
- results_file = urllib2.urlopen(results_file_url)
- info = results_file.info()
- old_results = results_file.read()
- except urllib2.HTTPError, http_error:
- # A non-4xx status code means the bot is hosed for some reason
- # and we can't grab the results.json file off of it.
- if (http_error.code < 400 and http_error.code >= 500):
- error = http_error
- except urllib2.URLError, url_error:
- error = url_error
+ results_file_url = (self.URL_FOR_TEST_LIST_JSON %
+ (urllib2.quote(self._test_results_server),
+ urllib2.quote(self._builder_name),
+ self.RESULTS_FILENAME,
+ urllib2.quote(self._test_type)))
+
+ try:
+ results_file = urllib2.urlopen(results_file_url)
+ info = results_file.info()
+ old_results = results_file.read()
+ except urllib2.HTTPError, http_error:
+ # A non-4xx status code means the bot is hosed for some reason
+ # and we can't grab the results.json file off of it.
+ if (http_error.code < 400 and http_error.code >= 500):
+ error = http_error
+ except urllib2.URLError, url_error:
+ error = url_error
if old_results:
# Strip the prefix and suffix so we can get the actual JSON object.
@@ -490,7 +458,7 @@ class JSONResultsGeneratorBase(object):
int(time.time()),
self.TIME)
- def _insert_test_time_and_result(self, test_name, tests, incremental=False):
+ def _insert_test_time_and_result(self, test_name, tests):
""" Insert a test item with its results to the given tests dictionary.
Args:
@@ -514,11 +482,6 @@ class JSONResultsGeneratorBase(object):
else:
thisTest[self.TIMES] = [[1, time]]
- # Don't normalize the incremental results json because we need results
- # for tests that pass or have no data from current run.
- if not incremental:
- self._normalize_results_json(thisTest, test_name, tests)
-
def _convert_json_to_current_version(self, results_json):
"""If the JSON does not match the current version, converts it to the
current version and adds in the new version number.
diff --git a/Tools/Scripts/webkitpy/layout_tests/layout_package/json_results_generator_unittest.py b/Tools/Scripts/webkitpy/layout_tests/layout_package/json_results_generator_unittest.py
index ce99765..95da8fb 100644
--- a/Tools/Scripts/webkitpy/layout_tests/layout_package/json_results_generator_unittest.py
+++ b/Tools/Scripts/webkitpy/layout_tests/layout_package/json_results_generator_unittest.py
@@ -94,7 +94,7 @@ class JSONGeneratorTest(unittest.TestCase):
failed_count_map = dict([(t, 1) for t in failed_tests])
# Test incremental json results
- incremental_json = generator.get_json(incremental=True)
+ incremental_json = generator.get_json()
self._verify_json_results(
tests_set,
test_timings,
@@ -106,33 +106,6 @@ class JSONGeneratorTest(unittest.TestCase):
incremental_json,
1)
- # Test aggregated json results
- generator.set_archived_results(self._json)
- json = generator.get_json(incremental=False)
- self._json = json
- self._num_runs += 1
- self._tests_set |= tests_set
- self._test_timings.update(test_timings)
- self._PASS_count += len(PASS_tests)
- self._DISABLED_count += len(DISABLED_tests)
- self._FLAKY_count += len(FLAKY_tests)
- self._fixable_count += len(DISABLED_tests | failed_tests)
-
- get = self._failed_count_map.get
- for test in failed_count_map.iterkeys():
- self._failed_count_map[test] = get(test, 0) + 1
-
- self._verify_json_results(
- self._tests_set,
- self._test_timings,
- self._failed_count_map,
- self._PASS_count,
- self._DISABLED_count,
- self._FLAKY_count,
- self._fixable_count,
- self._json,
- self._num_runs)
-
def _verify_json_results(self, tests_set, test_timings, failed_count_map,
PASS_count, DISABLED_count, FLAKY_count,
fixable_count,
diff --git a/Tools/Scripts/webkitpy/layout_tests/layout_package/manager_worker_broker.py b/Tools/Scripts/webkitpy/layout_tests/layout_package/manager_worker_broker.py
new file mode 100644
index 0000000..a0f252c
--- /dev/null
+++ b/Tools/Scripts/webkitpy/layout_tests/layout_package/manager_worker_broker.py
@@ -0,0 +1,282 @@
+# Copyright (C) 2011 Google Inc. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+# * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+"""Module for handling messages and concurrency for run-webkit-tests.
+
+This module implements a message broker that connects the manager
+(TestRunner2) to the workers: it provides a messaging abstraction and
+message loops (building on top of message_broker2), and handles starting
+workers by launching threads and/or processes depending on the
+requested configuration.
+
+There are a lot of classes and objects involved in a fully connected system.
+They interact more or less like:
+
+TestRunner2 --> _InlineManager ---> _InlineWorker <-> Worker
+ ^ \ / ^
+ | v v |
+ \-------------------- MessageBroker -------------/
+"""
+
+import logging
+import optparse
+import Queue
+import thread
+import threading
+import time
+
+
+# Handle Python < 2.6 where multiprocessing isn't available.
+#
+# _Multiprocessing_Process is needed so that _MultiProcessWorker
+# can be defined with or without multiprocessing.
+try:
+ import multiprocessing
+ _Multiprocessing_Process = multiprocessing.Process
+except ImportError:
+ multiprocessing = None
+ _Multiprocessing_Process = threading.Thread
+
+
+from webkitpy.layout_tests import port
+from webkitpy.layout_tests.layout_package import message_broker2
+
+
+_log = logging.getLogger(__name__)
+
+#
+# Topic names for Manager <-> Worker messaging
+#
+MANAGER_TOPIC = 'managers'
+ANY_WORKER_TOPIC = 'workers'
+
+
+def runtime_options():
+ """Return a list of optparse.Option objects for any runtime values used
+ by this module."""
+ options = [
+ optparse.make_option("--worker-model", action="store",
+ help=("controls worker model. Valid values are "
+ "'inline', 'threads', and 'processes'.")),
+ ]
+ return options
+
+
+def get(port, options, client, worker_class):
+ """Return a connection to a manager/worker message_broker
+
+ Args:
+ port - handle to layout_tests/port object for port-specific stuff
+ options - optparse argument for command-line options
+ client - message_broker2.BrokerClient implementation to dispatch
+ replies to.
+ worker_class - type of workers to create. This class must implement
+ the methods in AbstractWorker.
+ Returns:
+ A handle to an object that will talk to a message broker configured
+ for the normal manager/worker communication.
+ """
+ worker_model = options.worker_model
+ if worker_model == 'inline':
+ queue_class = Queue.Queue
+ manager_class = _InlineManager
+ elif worker_model == 'threads':
+ queue_class = Queue.Queue
+ manager_class = _ThreadedManager
+ elif worker_model == 'processes' and multiprocessing:
+ queue_class = multiprocessing.Queue
+ manager_class = _MultiProcessManager
+ else:
+ raise ValueError("unsupported value for --worker-model: %s" %
+ worker_model)
+
+ broker = message_broker2.Broker(options, queue_class)
+ return manager_class(broker, port, options, client, worker_class)
+
+
+class AbstractWorker(message_broker2.BrokerClient):
+ def __init__(self, broker_connection, worker_number, options):
+ """The constructor should be used to do any simple initialization
+ necessary, but should not do anything that creates data structures
+ that cannot be Pickled or sent across processes (like opening
+ files or sockets). Complex initialization should be done at the
+ start of the run() call.
+
+ Args:
+ broker_connection - handle to the BrokerConnection object creating
+ the worker and that can be used for messaging.
+ worker_number - identifier for this particular worker
+ options - command-line argument object from optparse"""
+
+ raise NotImplementedError
+
+ def run(self, port):
+ """Callback for the worker to start executing. Typically does any
+ remaining initialization and then calls broker_connection.run_message_loop()."""
+ raise NotImplementedError
+
+ def cancel(self):
+ """Called when possible to indicate to the worker to stop processing
+ messages and shut down. Note that workers may be stopped without this
+ method being called, so clients should not rely solely on this."""
+ raise NotImplementedError
+
+
+class _ManagerConnection(message_broker2.BrokerConnection):
+ def __init__(self, broker, options, client, worker_class):
+ """Base initialization for all Manager objects.
+
+ Args:
+ broker: handle to the message_broker2 object
+ options: command line options object
+ client: callback object (the caller)
+ worker_class: class object to use to create workers.
+ """
+ message_broker2.BrokerConnection.__init__(self, broker, client,
+ MANAGER_TOPIC, ANY_WORKER_TOPIC)
+ self._options = options
+ self._worker_class = worker_class
+
+ def start_worker(self, worker_number):
+ raise NotImplementedError
+
+
+class _InlineManager(_ManagerConnection):
+ def __init__(self, broker, port, options, client, worker_class):
+ _ManagerConnection.__init__(self, broker, options, client, worker_class)
+ self._port = port
+ self._inline_worker = None
+
+ def start_worker(self, worker_number):
+ self._inline_worker = _InlineWorkerConnection(self._broker, self._port,
+ self._client, self._worker_class, worker_number)
+ return self._inline_worker
+
+ def run_message_loop(self, delay_secs=None):
+ # Note that delay_secs is ignored in this case since we can't easily
+ # implement it.
+ self._inline_worker.run()
+ self._broker.run_all_pending(MANAGER_TOPIC, self._client)
+
+
+class _ThreadedManager(_ManagerConnection):
+ def __init__(self, broker, port, options, client, worker_class):
+ _ManagerConnection.__init__(self, broker, options, client, worker_class)
+ self._port = port
+
+ def start_worker(self, worker_number):
+ worker_connection = _ThreadedWorkerConnection(self._broker, self._port,
+ self._worker_class, worker_number)
+ worker_connection.start()
+ return worker_connection
+
+
+class _MultiProcessManager(_ManagerConnection):
+ def __init__(self, broker, port, options, client, worker_class):
+ # Note that this class does not keep a handle to the actual port
+ # object, because it isn't Picklable. Instead it keeps the port
+ # name and recreates the port in the child process from the name
+ # and options.
+ _ManagerConnection.__init__(self, broker, options, client, worker_class)
+ self._platform_name = port.real_name()
+
+ def start_worker(self, worker_number):
+ worker_connection = _MultiProcessWorkerConnection(self._broker, self._platform_name,
+ self._worker_class, worker_number, self._options)
+ worker_connection.start()
+ return worker_connection
+
+
+class _WorkerConnection(message_broker2.BrokerConnection):
+ def __init__(self, broker, worker_class, worker_number, options):
+ self._client = worker_class(self, worker_number, options)
+ self.name = self._client.name()
+ message_broker2.BrokerConnection.__init__(self, broker, self._client,
+ ANY_WORKER_TOPIC, MANAGER_TOPIC)
+
+ def yield_to_broker(self):
+ pass
+
+
+class _InlineWorkerConnection(_WorkerConnection):
+ def __init__(self, broker, port, manager_client, worker_class, worker_number):
+ _WorkerConnection.__init__(self, broker, worker_class, worker_number, port._options)
+ self._port = port
+ self._manager_client = manager_client
+
+ def run(self):
+ self._client.run(self._port)
+
+ def yield_to_broker(self):
+ self._broker.run_all_pending(MANAGER_TOPIC, self._manager_client)
+
+
+class _Thread(threading.Thread):
+ def __init__(self, worker_connection, port, client):
+ threading.Thread.__init__(self)
+ self._worker_connection = worker_connection
+ self._port = port
+ self._client = client
+
+ def run(self):
+ # FIXME: We can remove this once everyone is on 2.6.
+ if not hasattr(self, 'ident'):
+ self.ident = thread.get_ident()
+ self._client.run(self._port)
+
+
+class _ThreadedWorkerConnection(_WorkerConnection):
+ def __init__(self, broker, port, worker_class, worker_number):
+ _WorkerConnection.__init__(self, broker, worker_class, worker_number, port._options)
+ self._thread = _Thread(self, port, self._client)
+
+ def start(self):
+ self._thread.start()
+
+
+class _Process(_Multiprocessing_Process):
+ def __init__(self, worker_connection, platform_name, options, client):
+ _Multiprocessing_Process.__init__(self)
+ self._worker_connection = worker_connection
+ self._platform_name = platform_name
+ self._options = options
+ self._client = client
+
+ def run(self):
+ logging.basicConfig()
+ port_obj = port.get(self._platform_name, self._options)
+ self._client.run(port_obj)
+
+
+class _MultiProcessWorkerConnection(_WorkerConnection):
+ def __init__(self, broker, platform_name, worker_class, worker_number, options):
+ _WorkerConnection.__init__(self, broker, worker_class, worker_number, options)
+ self._proc = _Process(self, platform_name, options, self._client)
+
+ def start(self):
+ self._proc.start()
diff --git a/Tools/Scripts/webkitpy/layout_tests/layout_package/manager_worker_broker_unittest.py b/Tools/Scripts/webkitpy/layout_tests/layout_package/manager_worker_broker_unittest.py
new file mode 100644
index 0000000..ffbe081
--- /dev/null
+++ b/Tools/Scripts/webkitpy/layout_tests/layout_package/manager_worker_broker_unittest.py
@@ -0,0 +1,227 @@
+# 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 optparse
+import Queue
+import sys
+import unittest
+
+try:
+ import multiprocessing
+except ImportError:
+ multiprocessing = None
+
+
+from webkitpy.common.system import outputcapture
+
+from webkitpy.layout_tests import port
+from webkitpy.layout_tests.layout_package import manager_worker_broker
+from webkitpy.layout_tests.layout_package import message_broker2
+
+
+class TestWorker(manager_worker_broker.AbstractWorker):
+ def __init__(self, broker_connection, worker_number, options):
+ self._broker_connection = broker_connection
+ self._options = options
+ self._worker_number = worker_number
+ self._name = 'TestWorker/%d' % worker_number
+ self._stopped = False
+
+ def handle_stop(self, src):
+ self._stopped = True
+
+ def handle_test(self, src, an_int, a_str):
+ assert an_int == 1
+ assert a_str == "hello, world"
+ self._broker_connection.post_message('test', 2, 'hi, everybody')
+
+ def is_done(self):
+ return self._stopped
+
+ def name(self):
+ return self._name
+
+ def start(self):
+ pass
+
+ def run(self, port):
+ try:
+ self._broker_connection.run_message_loop()
+ self._broker_connection.yield_to_broker()
+ self._broker_connection.post_message('done')
+ except Exception, e:
+ self._broker_connection.post_message('exception', (type(e), str(e), None))
+
+
+def get_options(worker_model):
+ option_list = manager_worker_broker.runtime_options()
+ parser = optparse.OptionParser(option_list=option_list)
+ options, args = parser.parse_args(args=['--worker-model', worker_model])
+ return options
+
+
+def make_broker(manager, worker_model):
+ options = get_options(worker_model)
+ return manager_worker_broker.get(port.get("test"), options, manager,
+ TestWorker)
+
+
+class FunctionTests(unittest.TestCase):
+ def test_get__inline(self):
+ self.assertTrue(make_broker(self, 'inline') is not None)
+
+ def test_get__threads(self):
+ self.assertTrue(make_broker(self, 'threads') is not None)
+
+ def test_get__processes(self):
+ if multiprocessing:
+ self.assertTrue(make_broker(self, 'processes') is not None)
+ else:
+ self.assertRaises(ValueError, make_broker, self, 'processes')
+
+ def test_get__unknown(self):
+ self.assertRaises(ValueError, make_broker, self, 'unknown')
+
+
+class _TestsMixin(object):
+ """Mixin class that implements a series of tests to enforce the
+ contract all implementations must follow."""
+
+ #
+ # Methods to implement the Manager side of the ClientInterface
+ #
+ def name(self):
+ return 'Tester'
+
+ def is_done(self):
+ return self._done
+
+ #
+ # Handlers for the messages the TestWorker may send.
+ #
+ def handle_done(self, src):
+ self._done = True
+
+ def handle_test(self, src, an_int, a_str):
+ self._an_int = an_int
+ self._a_str = a_str
+
+ def handle_exception(self, src, exc_info):
+ self._exception = exc_info
+ self._done = True
+
+ #
+ # Testing helper methods
+ #
+ def setUp(self):
+ self._an_int = None
+ self._a_str = None
+ self._broker = None
+ self._done = False
+ self._exception = None
+ self._worker_model = None
+
+ def make_broker(self):
+ self._broker = make_broker(self, self._worker_model)
+
+ #
+ # Actual unit tests
+ #
+ def test_done(self):
+ if not self._worker_model:
+ return
+ self.make_broker()
+ worker = self._broker.start_worker(0)
+ self._broker.post_message('test', 1, 'hello, world')
+ self._broker.post_message('stop')
+ self._broker.run_message_loop()
+ self.assertTrue(self.is_done())
+ self.assertEqual(self._an_int, 2)
+ self.assertEqual(self._a_str, 'hi, everybody')
+
+ def test_unknown_message(self):
+ if not self._worker_model:
+ return
+ self.make_broker()
+ worker = self._broker.start_worker(0)
+ self._broker.post_message('unknown')
+ self._broker.run_message_loop()
+
+ self.assertTrue(self.is_done())
+ self.assertEquals(self._exception[0], ValueError)
+ self.assertEquals(self._exception[1],
+ "TestWorker/0: received message 'unknown' it couldn't handle")
+
+
+class InlineBrokerTests(_TestsMixin, unittest.TestCase):
+ def setUp(self):
+ _TestsMixin.setUp(self)
+ self._worker_model = 'inline'
+
+
+class MultiProcessBrokerTests(_TestsMixin, unittest.TestCase):
+ def setUp(self):
+ _TestsMixin.setUp(self)
+ if multiprocessing:
+ self._worker_model = 'processes'
+ else:
+ self._worker_model = None
+
+ def queue(self):
+ return multiprocessing.Queue()
+
+
+class ThreadedBrokerTests(_TestsMixin, unittest.TestCase):
+ def setUp(self):
+ _TestsMixin.setUp(self)
+ self._worker_model = 'threads'
+
+
+class FunctionsTest(unittest.TestCase):
+ def test_runtime_options(self):
+ option_list = manager_worker_broker.runtime_options()
+ parser = optparse.OptionParser(option_list=option_list)
+ options, args = parser.parse_args([])
+ self.assertTrue(options)
+
+
+class InterfaceTest(unittest.TestCase):
+ # These tests mostly exist to pacify coverage.
+
+ # FIXME: There must be a better way to do this and also verify
+ # that classes do implement every abstract method in an interface.
+ def test_managerconnection_is_abstract(self):
+ # Test that all the base class methods are abstract and have the
+ # signature we expect.
+ broker = make_broker(self, 'inline')
+ obj = manager_worker_broker._ManagerConnection(broker._broker, None, self, None)
+ self.assertRaises(NotImplementedError, obj.start_worker, 0)
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/Tools/Scripts/webkitpy/layout_tests/layout_package/message_broker.py b/Tools/Scripts/webkitpy/layout_tests/layout_package/message_broker.py
index 481c617..66a7aa8 100644
--- a/Tools/Scripts/webkitpy/layout_tests/layout_package/message_broker.py
+++ b/Tools/Scripts/webkitpy/layout_tests/layout_package/message_broker.py
@@ -41,9 +41,9 @@ requested configuration.
"""
import logging
-import sys
import time
-import traceback
+
+from webkitpy.common.system import stack_utils
import dump_render_tree_thread
@@ -137,6 +137,7 @@ class MultiThreadedBroker(WorkerMessageBroker):
def run_message_loop(self):
threads = self._threads()
+ wedged_threads = set()
# Loop through all the threads waiting for them to finish.
some_thread_is_alive = True
@@ -145,11 +146,15 @@ class MultiThreadedBroker(WorkerMessageBroker):
t = time.time()
for thread in threads:
if thread.isAlive():
+ if thread in wedged_threads:
+ continue
+
some_thread_is_alive = True
next_timeout = thread.next_timeout()
if next_timeout and t > next_timeout:
- log_wedged_worker(thread.getName(), thread.id())
+ stack_utils.log_thread_state(_log.error, thread.getName(), thread.id(), "is wedged")
thread.clear_next_timeout()
+ wedged_threads.add(thread)
exception_info = thread.exception_info()
if exception_info is not None:
@@ -164,34 +169,10 @@ class MultiThreadedBroker(WorkerMessageBroker):
if some_thread_is_alive:
time.sleep(0.01)
+ if wedged_threads:
+ _log.warning("All remaining threads are wedged, bailing out.")
+
def cancel_workers(self):
threads = self._threads()
for thread in threads:
thread.cancel()
-
-
-def log_wedged_worker(name, id):
- """Log information about the given worker state."""
- stack = _find_thread_stack(id)
- assert(stack is not None)
- _log.error("")
- _log.error("%s (tid %d) is wedged" % (name, id))
- _log_stack(stack)
- _log.error("")
-
-
-def _find_thread_stack(id):
- """Returns a stack object that can be used to dump a stack trace for
- the given thread id (or None if the id is not found)."""
- for thread_id, stack in sys._current_frames().items():
- if thread_id == id:
- return stack
- return None
-
-
-def _log_stack(stack):
- """Log a stack trace to log.error()."""
- for filename, lineno, name, line in traceback.extract_stack(stack):
- _log.error('File: "%s", line %d, in %s' % (filename, lineno, name))
- if line:
- _log.error(' %s' % line.strip())
diff --git a/Tools/Scripts/webkitpy/layout_tests/layout_package/message_broker2.py b/Tools/Scripts/webkitpy/layout_tests/layout_package/message_broker2.py
new file mode 100644
index 0000000..ec3c970
--- /dev/null
+++ b/Tools/Scripts/webkitpy/layout_tests/layout_package/message_broker2.py
@@ -0,0 +1,196 @@
+# Copyright (C) 2011 Google Inc. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+# * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+"""Module for handling messaging for run-webkit-tests.
+
+This module implements a simple message broker abstraction that will be
+used to coordinate messages between the main run-webkit-tests thread
+(aka TestRunner) and the individual worker threads (previously known as
+dump_render_tree_threads).
+
+The broker simply distributes messages onto topics (named queues); the actual
+queues themselves are provided by the caller, as the queue's implementation
+requirements varies vary depending on the desired concurrency model
+(none/threads/processes).
+
+In order for shared-nothing messaging between processing to be possible,
+Messages must be picklable.
+
+The module defines one interface and two classes. Callers of this package
+must implement the BrokerClient interface, and most callers will create
+BrokerConnections as well as Brokers.
+
+The classes relate to each other as:
+
+ BrokerClient ------> BrokerConnection
+ ^ |
+ | v
+ \---------------- Broker
+
+(The BrokerClient never calls broker directly after it is created, only
+BrokerConnection. BrokerConnection passes a reference to BrokerClient to
+Broker, and Broker only invokes that reference, never talking directly to
+BrokerConnection).
+"""
+
+import cPickle
+import logging
+import Queue
+import time
+
+
+_log = logging.getLogger(__name__)
+
+
+class BrokerClient(object):
+ """Abstract base class / interface that all message broker clients must
+ implement. In addition to the methods below, by convention clients
+ implement routines of the signature type
+
+ handle_MESSAGE_NAME(self, src, ...):
+
+ where MESSAGE_NAME matches the string passed to post_message(), and
+ src indicates the name of the sender. If the message contains values in
+ the message body, those will be provided as optparams."""
+
+ def __init__(self, *optargs, **kwargs):
+ raise NotImplementedError
+
+ def is_done(self):
+ """Called from inside run_message_loop() to indicate whether to exit."""
+ raise NotImplementedError
+
+ def name(self):
+ """Return a name that identifies the client."""
+ raise NotImplementedError
+
+
+class Broker(object):
+ """Brokers provide the basic model of a set of topics. Clients can post a
+ message to any topic using post_message(), and can process messages on one
+ topic at a time using run_message_loop()."""
+
+ def __init__(self, options, queue_maker):
+ """Args:
+ options: a runtime option class from optparse
+ queue_maker: a factory method that returns objects implementing a
+ Queue interface (put()/get()).
+ """
+ self._options = options
+ self._queue_maker = queue_maker
+ self._topics = {}
+
+ def add_topic(self, topic_name):
+ if topic_name not in self._topics:
+ self._topics[topic_name] = self._queue_maker()
+
+ def _get_queue_for_topic(self, topic_name):
+ return self._topics[topic_name]
+
+ def post_message(self, client, topic_name, message_name, *message_args):
+ """Post a message to the appropriate topic name.
+
+ Messages have a name and a tuple of optional arguments. Both must be picklable."""
+ message = _Message(client.name(), topic_name, message_name, message_args)
+ queue = self._get_queue_for_topic(topic_name)
+ queue.put(_Message.dumps(message))
+
+ def run_message_loop(self, topic_name, client, delay_secs=None):
+ """Loop processing messages until client.is_done() or delay passes.
+
+ To run indefinitely, set delay_secs to None."""
+ assert delay_secs is None or delay_secs > 0
+ self._run_loop(topic_name, client, block=True, delay_secs=delay_secs)
+
+ def run_all_pending(self, topic_name, client):
+ """Process messages until client.is_done() or caller would block."""
+ self._run_loop(topic_name, client, block=False, delay_secs=None)
+
+ def _run_loop(self, topic_name, client, block, delay_secs):
+ queue = self._get_queue_for_topic(topic_name)
+ while not client.is_done():
+ try:
+ s = queue.get(block, delay_secs)
+ except Queue.Empty:
+ return
+ msg = _Message.loads(s)
+ self._dispatch_message(msg, client)
+
+ def _dispatch_message(self, message, client):
+ if not hasattr(client, 'handle_' + message.name):
+ raise ValueError(
+ "%s: received message '%s' it couldn't handle" %
+ (client.name(), message.name))
+ optargs = message.args
+ message_handler = getattr(client, 'handle_' + message.name)
+ message_handler(message.src, *optargs)
+
+
+class _Message(object):
+ @staticmethod
+ def loads(str):
+ obj = cPickle.loads(str)
+ assert(isinstance(obj, _Message))
+ return obj
+
+ def __init__(self, src, topic_name, message_name, message_args):
+ self.src = src
+ self.topic_name = topic_name
+ self.name = message_name
+ self.args = message_args
+
+ def dumps(self):
+ return cPickle.dumps(self)
+
+ def __repr__(self):
+ return ("_Message(from='%s', topic_name='%s', message_name='%s')" %
+ (self.src, self.topic_name, self.name))
+
+
+class BrokerConnection(object):
+ """BrokerConnection provides a connection-oriented facade on top of a
+ Broker, so that callers don't have to repeatedly pass the same topic
+ names over and over."""
+
+ def __init__(self, broker, client, run_topic, post_topic):
+ """Create a BrokerConnection on top of a Broker. Note that the Broker
+ is passed in rather than created so that a single Broker can be used
+ by multiple BrokerConnections."""
+ self._broker = broker
+ self._client = client
+ self._post_topic = post_topic
+ self._run_topic = run_topic
+ broker.add_topic(run_topic)
+ broker.add_topic(post_topic)
+
+ def run_message_loop(self, delay_secs=None):
+ self._broker.run_message_loop(self._run_topic, self._client, delay_secs)
+
+ def post_message(self, message_name, *message_args):
+ self._broker.post_message(self._client, self._post_topic,
+ message_name, *message_args)
diff --git a/Tools/Scripts/webkitpy/layout_tests/layout_package/message_broker2_unittest.py b/Tools/Scripts/webkitpy/layout_tests/layout_package/message_broker2_unittest.py
new file mode 100644
index 0000000..0e0a88d
--- /dev/null
+++ b/Tools/Scripts/webkitpy/layout_tests/layout_package/message_broker2_unittest.py
@@ -0,0 +1,83 @@
+# Copyright (C) 2011 Google Inc. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+# * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+import unittest
+
+from webkitpy.layout_tests.layout_package import message_broker2
+
+# This file exists to test routines that aren't necessarily covered elsewhere;
+# most of the testing of message_broker2 will be covered under the tests in
+# the manager_worker_broker module.
+
+
+class MessageTest(unittest.TestCase):
+ def test__no_body(self):
+ msg = message_broker2._Message('src', 'topic_name', 'message_name', None)
+ self.assertTrue(repr(msg))
+ s = msg.dumps()
+ new_msg = message_broker2._Message.loads(s)
+ self.assertEqual(new_msg.name, 'message_name')
+ self.assertEqual(new_msg.args, None)
+ self.assertEqual(new_msg.topic_name, 'topic_name')
+ self.assertEqual(new_msg.src, 'src')
+
+ def test__body(self):
+ msg = message_broker2._Message('src', 'topic_name', 'message_name',
+ ('body', 0))
+ self.assertTrue(repr(msg))
+ s = msg.dumps()
+ new_msg = message_broker2._Message.loads(s)
+ self.assertEqual(new_msg.name, 'message_name')
+ self.assertEqual(new_msg.args, ('body', 0))
+ self.assertEqual(new_msg.topic_name, 'topic_name')
+ self.assertEqual(new_msg.src, 'src')
+
+
+class InterfaceTest(unittest.TestCase):
+ # These tests mostly exist to pacify coverage.
+
+ # FIXME: There must be a better way to do this and also verify
+ # that classes do implement every abstract method in an interface.
+
+ def test_brokerclient_is_abstract(self):
+ # Test that we can't create an instance directly.
+ self.assertRaises(NotImplementedError, message_broker2.BrokerClient)
+
+ class TestClient(message_broker2.BrokerClient):
+ def __init__(self):
+ pass
+
+ # Test that all the base class methods are abstract and have the
+ # signature we expect.
+ obj = TestClient()
+ self.assertRaises(NotImplementedError, obj.is_done)
+ self.assertRaises(NotImplementedError, obj.name)
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/Tools/Scripts/webkitpy/layout_tests/layout_package/message_broker_unittest.py b/Tools/Scripts/webkitpy/layout_tests/layout_package/message_broker_unittest.py
index 6f04fd3..f4cb5d2 100644
--- a/Tools/Scripts/webkitpy/layout_tests/layout_package/message_broker_unittest.py
+++ b/Tools/Scripts/webkitpy/layout_tests/layout_package/message_broker_unittest.py
@@ -84,7 +84,6 @@ class TestThread(threading.Thread):
def next_timeout(self):
if self._timeout:
- self._timeout_queue.put('done')
return time.time() - 10
return time.time()
@@ -125,7 +124,12 @@ class MultiThreadedBrokerTest(unittest.TestCase):
child_thread.start()
started_msg = starting_queue.get()
stopping_queue.put(msg)
- return broker.run_message_loop()
+ res = broker.run_message_loop()
+ if msg == 'Timeout':
+ child_thread._timeout_queue.put('done')
+ child_thread.join(1.0)
+ self.assertFalse(child_thread.isAlive())
+ return res
def test_basic(self):
interrupted = self.run_one_thread('')
@@ -135,48 +139,22 @@ class MultiThreadedBrokerTest(unittest.TestCase):
self.assertRaises(KeyboardInterrupt, self.run_one_thread, 'KeyboardInterrupt')
def test_timeout(self):
+ # Because the timeout shows up as a wedged thread, this also tests
+ # log_wedged_worker().
oc = outputcapture.OutputCapture()
- oc.capture_output()
- interrupted = self.run_one_thread('Timeout')
- self.assertFalse(interrupted)
- oc.restore_output()
-
- def test_exception(self):
- self.assertRaises(ValueError, self.run_one_thread, 'Exception')
-
-
-class Test(unittest.TestCase):
- def test_find_thread_stack_found(self):
- id, stack = sys._current_frames().items()[0]
- found_stack = message_broker._find_thread_stack(id)
- self.assertNotEqual(found_stack, None)
-
- def test_find_thread_stack_not_found(self):
- found_stack = message_broker._find_thread_stack(0)
- self.assertEqual(found_stack, None)
-
- def test_log_wedged_worker(self):
- oc = outputcapture.OutputCapture()
- oc.capture_output()
+ stdout, stderr = oc.capture_output()
logger = message_broker._log
astream = array_stream.ArrayStream()
handler = TestHandler(astream)
logger.addHandler(handler)
+ interrupted = self.run_one_thread('Timeout')
+ stdout, stderr = oc.restore_output()
+ self.assertFalse(interrupted)
+ logger.handlers.remove(handler)
+ self.assertTrue('All remaining threads are wedged, bailing out.' in astream.get())
- starting_queue = Queue.Queue()
- stopping_queue = Queue.Queue()
- child_thread = TestThread(starting_queue, stopping_queue)
- child_thread.start()
- msg = starting_queue.get()
-
- message_broker.log_wedged_worker(child_thread.getName(),
- child_thread.id())
- stopping_queue.put('')
- child_thread.join(timeout=1.0)
-
- self.assertFalse(astream.empty())
- self.assertFalse(child_thread.isAlive())
- oc.restore_output()
+ def test_exception(self):
+ self.assertRaises(ValueError, self.run_one_thread, 'Exception')
if __name__ == '__main__':
diff --git a/Tools/Scripts/webkitpy/layout_tests/layout_package/printing_unittest.py b/Tools/Scripts/webkitpy/layout_tests/layout_package/printing_unittest.py
index 12a786e..7ab6da8 100644
--- a/Tools/Scripts/webkitpy/layout_tests/layout_package/printing_unittest.py
+++ b/Tools/Scripts/webkitpy/layout_tests/layout_package/printing_unittest.py
@@ -144,7 +144,7 @@ class Testprinter(unittest.TestCase):
test in tests]
expectations = test_expectations.TestExpectations(
self._port, test_paths, expectations_str,
- self._port.test_platform_name(), is_debug_mode=False,
+ self._port.test_configuration(),
is_lint_mode=False)
rs = result_summary.ResultSummary(expectations, test_paths)
@@ -363,7 +363,7 @@ class Testprinter(unittest.TestCase):
def test_print_progress__detailed(self):
tests = ['passes/text.html', 'failures/expected/timeout.html',
'failures/expected/crash.html']
- expectations = 'failures/expected/timeout.html = TIMEOUT'
+ expectations = 'BUGX : failures/expected/timeout.html = TIMEOUT'
# first, test that it is disabled properly
# should still print one-line-progress
@@ -569,8 +569,8 @@ class Testprinter(unittest.TestCase):
self.assertFalse(out.empty())
expectations = """
-failures/expected/crash.html = CRASH
-failures/expected/timeout.html = TIMEOUT
+BUGX : failures/expected/crash.html = CRASH
+BUGX : failures/expected/timeout.html = TIMEOUT
"""
err.reset()
out.reset()
diff --git a/Tools/Scripts/webkitpy/layout_tests/layout_package/single_test_runner.py b/Tools/Scripts/webkitpy/layout_tests/layout_package/single_test_runner.py
new file mode 100644
index 0000000..96e3ee6
--- /dev/null
+++ b/Tools/Scripts/webkitpy/layout_tests/layout_package/single_test_runner.py
@@ -0,0 +1,322 @@
+# Copyright (C) 2011 Google Inc. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+# * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+import logging
+import threading
+import time
+
+from webkitpy.layout_tests.port import base
+
+from webkitpy.layout_tests.test_types import text_diff
+from webkitpy.layout_tests.test_types import image_diff
+
+from webkitpy.layout_tests.layout_package import test_failures
+from webkitpy.layout_tests.layout_package.test_results import TestResult
+
+
+_log = logging.getLogger(__name__)
+
+
+class ExpectedDriverOutput:
+ """Groups information about an expected driver output."""
+ def __init__(self, text, image, image_hash):
+ self.text = text
+ self.image = image
+ self.image_hash = image_hash
+
+
+class SingleTestRunner:
+
+ def __init__(self, options, port, worker_name, worker_number):
+ self._options = options
+ self._port = port
+ self._worker_name = worker_name
+ self._worker_number = worker_number
+ self._driver = None
+ self._test_types = []
+ self.has_http_lock = False
+ for cls in self._get_test_type_classes():
+ self._test_types.append(cls(self._port,
+ self._options.results_directory))
+
+ def cleanup(self):
+ self.kill_dump_render_tree()
+ if self.has_http_lock:
+ self.stop_servers_with_lock()
+
+ def _get_test_type_classes(self):
+ classes = [text_diff.TestTextDiff]
+ if self._options.pixel_tests:
+ classes.append(image_diff.ImageDiff)
+ return classes
+
+ def timeout(self, test_input):
+ # We calculate how long we expect the test to take.
+ #
+ # The DumpRenderTree watchdog uses 2.5x the timeout; we want to be
+ # larger than that. We also add a little more padding if we're
+ # running tests in a separate thread.
+ #
+ # Note that we need to convert the test timeout from a
+ # string value in milliseconds to a float for Python.
+ driver_timeout_sec = 3.0 * float(test_input.timeout) / 1000.0
+ if not self._options.run_singly:
+ return driver_timeout_sec
+
+ thread_padding_sec = 1.0
+ thread_timeout_sec = driver_timeout_sec + thread_padding_sec
+ return thread_timeout_sec
+
+ def run_test(self, test_input, timeout):
+ if self._options.run_singly:
+ return self._run_test_in_another_thread(test_input, timeout)
+ else:
+ return self._run_test_in_this_thread(test_input)
+ return result
+
+ def _run_test_in_another_thread(self, test_input, thread_timeout_sec):
+ """Run a test in a separate thread, enforcing a hard time limit.
+
+ Since we can only detect the termination of a thread, not any internal
+ state or progress, we can only run per-test timeouts when running test
+ files singly.
+
+ Args:
+ test_input: Object containing the test filename and timeout
+ thread_timeout_sec: time to wait before killing the driver process.
+ Returns:
+ A TestResult
+ """
+ worker = self
+ result = None
+
+ driver = worker._port.create_driver(worker._worker_number)
+ driver.start()
+
+ class SingleTestThread(threading.Thread):
+ def run(self):
+ result = worker.run(test_input, driver)
+
+ thread = SingleTestThread()
+ thread.start()
+ thread.join(thread_timeout_sec)
+ if thread.isAlive():
+ # If join() returned with the thread still running, the
+ # DumpRenderTree is completely hung and there's nothing
+ # more we can do with it. We have to kill all the
+ # DumpRenderTrees to free it up. If we're running more than
+ # one DumpRenderTree thread, we'll end up killing the other
+ # DumpRenderTrees too, introducing spurious crashes. We accept
+ # that tradeoff in order to avoid losing the rest of this
+ # thread's results.
+ _log.error('Test thread hung: killing all DumpRenderTrees')
+
+ driver.stop()
+
+ if not result:
+ result = TestResult(test_input.filename, failures=[],
+ test_run_time=0, total_time_for_all_diffs=0, time_for_diffs={})
+ return result
+
+ def _run_test_in_this_thread(self, test_input):
+ """Run a single test file using a shared DumpRenderTree process.
+
+ Args:
+ test_input: Object containing the test filename, uri and timeout
+
+ Returns: a TestResult object.
+ """
+ # poll() is not threadsafe and can throw OSError due to:
+ # http://bugs.python.org/issue1731717
+ if not self._driver or self._driver.poll() is not None:
+ self._driver = self._port.create_driver(self._worker_number)
+ self._driver.start()
+ return self._run(self._driver, test_input)
+
+ def _expected_driver_output(self):
+ return ExpectedDriverOutput(self._port.expected_text(self._filename),
+ self._port.expected_image(self._filename),
+ self._port.expected_checksum(self._filename))
+
+ def _should_fetch_expected_checksum(self):
+ return (self._options.pixel_tests and
+ not (self._options.new_baseline or self._options.reset_results))
+
+ def _driver_input(self, test_input):
+ self._filename = test_input.filename
+ self._timeout = test_input.timeout
+ self._testname = self._port.relative_test_filename(test_input.filename)
+
+ # The image hash is used to avoid doing an image dump if the
+ # checksums match, so it should be set to a blank value if we
+ # are generating a new baseline. (Otherwise, an image from a
+ # previous run will be copied into the baseline."""
+ image_hash = None
+ if self._should_fetch_expected_checksum():
+ image_hash = self._port.expected_checksum(self._filename)
+ return base.DriverInput(self._filename, self._timeout, image_hash)
+
+ def _run(self, driver, test_input):
+ if self._options.new_baseline or self._options.reset_results:
+ return self._run_rebaseline(driver, test_input)
+ return self._run_compare_test(driver, test_input)
+
+ def _run_compare_test(self, driver, test_input):
+ driver_output = self._driver.run_test(self._driver_input(test_input))
+ return self._process_output(driver_output)
+
+ def _run_rebaseline(self, driver, test_input):
+ driver_output = self._driver.run_test(self._driver_input(test_input))
+ failures = self._handle_error(driver_output)
+ # FIXME: It the test crashed or timed out, it might be bettter to avoid
+ # to write new baselines.
+ self._save_baselines(driver_output)
+ return TestResult(self._filename, failures, driver_output.test_time)
+
+ def _save_baselines(self, driver_output):
+ # Although all test_shell/DumpRenderTree output should be utf-8,
+ # we do not ever decode it inside run-webkit-tests. For some tests
+ # DumpRenderTree may not output utf-8 text (e.g. webarchives).
+ self._save_baseline_data(driver_output.text, ".txt",
+ generate_new_baseline=self._options.new_baseline)
+ if self._options.pixel_tests and driver_output.image_hash:
+ self._save_baseline_data(driver_output.image, ".png",
+ generate_new_baseline=self._options.new_baseline)
+ self._save_baseline_data(driver_output.image_hash, ".checksum",
+ generate_new_baseline=self._options.new_baseline)
+
+ def _save_baseline_data(self, data, modifier, generate_new_baseline=True):
+ """Saves a new baseline file into the port's baseline directory.
+
+ The file will be named simply "<test>-expected<modifier>", suitable for
+ use as the expected results in a later run.
+
+ Args:
+ data: result to be saved as the new baseline
+ modifier: type of the result file, e.g. ".txt" or ".png"
+ generate_new_baseline: whether to enerate a new, platform-specific
+ baseline, or update the existing one
+ """
+
+ port = self._port
+ fs = port._filesystem
+ if generate_new_baseline:
+ relative_dir = fs.dirname(self._testname)
+ baseline_path = port.baseline_path()
+ output_dir = fs.join(baseline_path, relative_dir)
+ output_file = fs.basename(fs.splitext(self._filename)[0] +
+ "-expected" + modifier)
+ fs.maybe_make_directory(output_dir)
+ output_path = fs.join(output_dir, output_file)
+ _log.debug('writing new baseline result "%s"' % (output_path))
+ else:
+ output_path = port.expected_filename(self._filename, modifier)
+ _log.debug('resetting baseline result "%s"' % output_path)
+
+ port.update_baseline(output_path, data)
+
+ def _handle_error(self, driver_output):
+ failures = []
+ fs = self._port._filesystem
+ if driver_output.timeout:
+ failures.append(test_failures.FailureTimeout())
+ if driver_output.crash:
+ failures.append(test_failures.FailureCrash())
+ _log.debug("%s Stacktrace for %s:\n%s" % (self._worker_name, self._testname,
+ driver_output.error))
+ stack_filename = fs.join(self._options.results_directory, self._testname)
+ stack_filename = fs.splitext(stack_filename)[0] + "-stack.txt"
+ fs.maybe_make_directory(fs.dirname(stack_filename))
+ fs.write_text_file(stack_filename, driver_output.error)
+ elif driver_output.error:
+ _log.debug("%s %s output stderr lines:\n%s" % (self._worker_name, self._testname,
+ driver_output.error))
+ return failures
+
+ def _run_test(self):
+ driver_output = self._driver.run_test(self._driver_input())
+ return self._process_output(driver_output)
+
+ def _process_output(self, driver_output):
+ """Receives the output from a DumpRenderTree process, subjects it to a
+ number of tests, and returns a list of failure types the test produced.
+ Args:
+ driver_output: a DriverOutput object containing the output from the driver
+
+ Returns: a TestResult object
+ """
+ fs = self._port._filesystem
+ failures = self._handle_error(driver_output)
+ expected_driver_output = self._expected_driver_output()
+
+ # Check the output and save the results.
+ start_time = time.time()
+ time_for_diffs = {}
+ for test_type in self._test_types:
+ start_diff_time = time.time()
+ new_failures = test_type.compare_output(
+ self._port, self._filename, self._options, driver_output,
+ expected_driver_output)
+ # Don't add any more failures if we already have a crash, so we don't
+ # double-report those tests. We do double-report for timeouts since
+ # we still want to see the text and image output.
+ if not driver_output.crash:
+ failures.extend(new_failures)
+ time_for_diffs[test_type.__class__.__name__] = (
+ time.time() - start_diff_time)
+
+ total_time_for_all_diffs = time.time() - start_diff_time
+ return TestResult(self._filename, failures, driver_output.test_time,
+ total_time_for_all_diffs, time_for_diffs)
+
+ def start_servers_with_lock(self):
+ _log.debug('Acquiring 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.has_http_lock = True
+
+ def stop_servers_with_lock(self):
+ """Stop the servers and release http lock."""
+ if self.has_http_lock:
+ _log.debug('Stopping HTTP server ...')
+ self._port.stop_http_server()
+ _log.debug('Stopping WebSocket server ...')
+ self._port.stop_websocket_server()
+ _log.debug('Releasing server lock ...')
+ self._port.release_http_lock()
+ self.has_http_lock = False
+
+ def kill_dump_render_tree(self):
+ """Kill the DumpRenderTree process if it's running."""
+ if self._driver:
+ self._driver.stop()
+ self._driver = None
diff --git a/Tools/Scripts/webkitpy/layout_tests/layout_package/test_expectations.py b/Tools/Scripts/webkitpy/layout_tests/layout_package/test_expectations.py
index 806b663..494395a 100644
--- a/Tools/Scripts/webkitpy/layout_tests/layout_package/test_expectations.py
+++ b/Tools/Scripts/webkitpy/layout_tests/layout_package/test_expectations.py
@@ -31,6 +31,7 @@
for layout tests.
"""
+import itertools
import logging
import re
@@ -84,18 +85,16 @@ def remove_pixel_failures(expected_results):
class TestExpectations:
TEST_LIST = "test_expectations.txt"
- def __init__(self, port, tests, expectations, test_platform_name,
- is_debug_mode, is_lint_mode, overrides=None):
+ def __init__(self, port, tests, expectations, test_config,
+ is_lint_mode, overrides=None):
"""Loads and parses the test expectations given in the string.
Args:
port: handle to object containing platform-specific functionality
- test: list of all of the test files
+ tests: list of all of the test files
expectations: test expectations as a string
- test_platform_name: name of the platform to match expectations
- against. Note that this may be different than
- port.test_platform_name() when is_lint_mode is True.
- is_debug_mode: whether to use the DEBUG or RELEASE modifiers
- in the expectations
+ test_config: specific values to check against when
+ parsing the file (usually port.test_config(),
+ but may be different when linting or doing other things).
is_lint_mode: If True, just parse the expectations string
looking for errors.
overrides: test expectations that are allowed to override any
@@ -104,7 +103,7 @@ class TestExpectations:
and downstream expectations).
"""
self._expected_failures = TestExpectationsFile(port, expectations,
- tests, test_platform_name, is_debug_mode, is_lint_mode,
+ tests, test_config, is_lint_mode,
overrides=overrides)
# TODO(ojan): Allow for removing skipped tests when getting the list of
@@ -197,7 +196,7 @@ class ParseError(Exception):
return '\n'.join(map(str, self.errors))
def __repr__(self):
- return 'ParseError(fatal=%s, errors=%s)' % (fatal, errors)
+ return 'ParseError(fatal=%s, errors=%s)' % (self.fatal, self.errors)
class ModifiersAndExpectations:
@@ -302,29 +301,15 @@ class TestExpectationsFile:
'fail': FAIL,
'flaky': FLAKY}
- def __init__(self, port, expectations, full_test_list, test_platform_name,
- is_debug_mode, is_lint_mode, overrides=None):
- """
- expectations: Contents of the expectations file
- full_test_list: The list of all tests to be run pending processing of
- the expections for those tests.
- test_platform_name: name of the platform to match expectations
- against. Note that this may be different than
- port.test_platform_name() when is_lint_mode is True.
- is_debug_mode: Whether we testing a test_shell built debug mode.
- is_lint_mode: Whether this is just linting test_expecatations.txt.
- overrides: test expectations that are allowed to override any
- entries in |expectations|. This is used by callers
- that need to manage two sets of expectations (e.g., upstream
- and downstream expectations).
- """
+ def __init__(self, port, expectations, full_test_list,
+ test_config, is_lint_mode, overrides=None):
+ # See argument documentation in TestExpectation(), above.
self._port = port
self._fs = port._filesystem
self._expectations = expectations
self._full_test_list = full_test_list
- self._test_platform_name = test_platform_name
- self._is_debug_mode = is_debug_mode
+ self._test_config = test_config
self._is_lint_mode = is_lint_mode
self._overrides = overrides
self._errors = []
@@ -332,7 +317,9 @@ class TestExpectationsFile:
# Maps relative test paths as listed in the expectations file to a
# list of maps containing modifiers and expectations for each time
- # the test is listed in the expectations file.
+ # the test is listed in the expectations file. We use this to
+ # keep a representation of the entire list of expectations, even
+ # invalid ones.
self._all_expectations = {}
# Maps a test to its list of expectations.
@@ -345,7 +332,8 @@ class TestExpectationsFile:
# the options minus any bug or platform strings
self._test_to_modifiers = {}
- # Maps a test to the base path that it was listed with in the list.
+ # Maps a test to the base path that it was listed with in the list and
+ # the number of matches that base path had.
self._test_list_paths = {}
self._modifier_to_tests = self._dict_of_sets(self.MODIFIERS)
@@ -372,13 +360,7 @@ class TestExpectationsFile:
def _handle_any_read_errors(self):
if len(self._errors) or len(self._non_fatal_errors):
- if self._is_debug_mode:
- build_type = 'DEBUG'
- else:
- build_type = 'RELEASE'
- _log.error('')
- _log.error("FAILURES FOR PLATFORM: %s, BUILD_TYPE: %s" %
- (self._test_platform_name.upper(), build_type))
+ _log.error("FAILURES FOR %s" % str(self._test_config))
for error in self._errors:
_log.error(error)
@@ -394,11 +376,12 @@ class TestExpectationsFile:
expectations = set([PASS])
options = []
modifiers = []
+ num_matches = 0
if self._full_test_list:
for test in self._full_test_list:
if not test in self._test_list_paths:
- self._add_test(test, modifiers, expectations, options,
- overrides_allowed=False)
+ self._add_test(test, modifiers, num_matches, expectations,
+ options, overrides_allowed=False)
def _dict_of_sets(self, strings_to_constants):
"""Takes a dict of strings->constants and returns a dict mapping
@@ -505,7 +488,8 @@ class TestExpectationsFile:
_log.info(' new: %s', new_line)
elif action == ADD_PLATFORMS_EXCEPT_THIS:
parts = line.split(':')
- new_options = parts[0]
+ _log.info('Test updated: ')
+ _log.info(' old: %s', line)
for p in self._port.test_platform_names():
p = p.upper()
# This is a temp solution for rebaselining tool.
@@ -515,13 +499,11 @@ class TestExpectationsFile:
# TODO(victorw): Remove WIN-VISTA and WIN-7 once we have
# reliable Win 7 and Win Vista buildbots setup.
if not p in (platform.upper(), 'WIN-VISTA', 'WIN-7'):
- new_options += p + ' '
- new_line = ('%s:%s' % (new_options, parts[1]))
- f_new.append(new_line)
+ new_options = parts[0] + p + ' '
+ new_line = ('%s:%s' % (new_options, parts[1]))
+ f_new.append(new_line)
+ _log.info(' new: %s', new_line)
tests_updated += 1
- _log.info('Test updated: ')
- _log.info(' old: %s', line)
- _log.info(' new: %s', new_line)
_log.info('Total tests removed: %d', tests_removed)
_log.info('Total tests updated: %d', tests_updated)
@@ -537,12 +519,15 @@ class TestExpectationsFile:
options = []
if line.find(":") is -1:
- test_and_expectation = line.split("=")
- else:
- parts = line.split(":")
- options = self._get_options_list(parts[0])
- test_and_expectation = parts[1].split('=')
+ self._add_error(lineno, "Missing a ':'", line)
+ return (None, None, None)
+ parts = line.split(':')
+
+ # FIXME: verify that there is exactly one colon in the line.
+
+ options = self._get_options_list(parts[0])
+ test_and_expectation = parts[1].split('=')
test = test_and_expectation[0].strip()
if (len(test_and_expectation) is not 2):
self._add_error(lineno, "Missing expectations.",
@@ -588,69 +573,6 @@ class TestExpectationsFile:
return REMOVE_TEST
- def _has_valid_modifiers_for_current_platform(self, options, lineno,
- test_and_expectations, modifiers):
- """Returns true if the current platform is in the options list or if
- no platforms are listed and if there are no fatal errors in the
- options list.
-
- Args:
- options: List of lowercase options.
- lineno: The line in the file where the test is listed.
- test_and_expectations: The path and expectations for the test.
- modifiers: The set to populate with modifiers.
- """
- has_any_platform = False
- has_bug_id = False
- for option in options:
- if option in self.MODIFIERS:
- modifiers.add(option)
- elif option in self._port.test_platform_names():
- has_any_platform = True
- elif re.match(r'bug\d', option) != None:
- self._add_error(lineno, 'Bug must be either BUGCR, BUGWK, or BUGV8_ for test: %s' %
- option, test_and_expectations)
- elif option.startswith('bug'):
- has_bug_id = True
- elif option not in self.BUILD_TYPES:
- self._add_error(lineno, 'Invalid modifier for test: %s' %
- option, test_and_expectations)
-
- if has_any_platform and not self._match_platform(options):
- return False
-
- if not has_bug_id and 'wontfix' not in options:
- # TODO(ojan): Turn this into an AddError call once all the
- # tests have BUG identifiers.
- self._log_non_fatal_error(lineno, 'Test lacks BUG modifier.',
- test_and_expectations)
-
- if 'release' in options or 'debug' in options:
- if self._is_debug_mode and 'debug' not in options:
- return False
- if not self._is_debug_mode and 'release' not in options:
- return False
-
- if self._is_lint_mode and 'rebaseline' in options:
- self._add_error(lineno,
- 'REBASELINE should only be used for running rebaseline.py. '
- 'Cannot be checked in.', test_and_expectations)
-
- return True
-
- def _match_platform(self, options):
- """Match the list of options against our specified platform. If any
- of the options prefix-match self._platform, return True. This handles
- the case where a test is marked WIN and the platform is WIN-VISTA.
-
- Args:
- options: list of options
- """
- for opt in options:
- if self._test_platform_name.startswith(opt):
- return True
- return False
-
def _add_to_all_expectations(self, test, options, expectations):
# Make all paths unix-style so the dashboard doesn't need to.
test = test.replace('\\', '/')
@@ -663,54 +585,43 @@ class TestExpectationsFile:
"""For each test in an expectations iterable, generate the
expectations for it."""
lineno = 0
+ matcher = ModifierMatcher(self._test_config)
for line in expectations:
lineno += 1
+ self._process_line(line, lineno, matcher, overrides_allowed)
- test_list_path, options, expectations = \
- self.parse_expectations_line(line, lineno)
- if not expectations:
- continue
+ def _process_line(self, line, lineno, matcher, overrides_allowed):
+ test_list_path, options, expectations = \
+ self.parse_expectations_line(line, lineno)
+ if not expectations:
+ return
- self._add_to_all_expectations(test_list_path,
- " ".join(options).upper(),
- " ".join(expectations).upper())
+ self._add_to_all_expectations(test_list_path,
+ " ".join(options).upper(),
+ " ".join(expectations).upper())
- modifiers = set()
- if options and not self._has_valid_modifiers_for_current_platform(
- options, lineno, test_list_path, modifiers):
- continue
+ num_matches = self._check_options(matcher, options, lineno,
+ test_list_path)
+ if num_matches == ModifierMatcher.NO_MATCH:
+ return
- expectations = self._parse_expectations(expectations, lineno,
- test_list_path)
+ expectations = self._parse_expectations(expectations, lineno,
+ test_list_path)
- if 'slow' in options and TIMEOUT in expectations:
- self._add_error(lineno,
- 'A test can not be both slow and timeout. If it times out '
- 'indefinitely, then it should be just timeout.',
- test_list_path)
+ self._check_options_against_expectations(options, expectations,
+ lineno, test_list_path)
- full_path = self._fs.join(self._port.layout_tests_dir(),
- test_list_path)
- full_path = self._fs.normpath(full_path)
- # WebKit's way of skipping tests is to add a -disabled suffix.
- # So we should consider the path existing if the path or the
- # -disabled version exists.
- if (not self._port.path_exists(full_path)
- and not self._port.path_exists(full_path + '-disabled')):
- # Log a non fatal error here since you hit this case any
- # time you update test_expectations.txt without syncing
- # the LayoutTests directory
- self._log_non_fatal_error(lineno, 'Path does not exist.',
- test_list_path)
- continue
+ if self._check_path_does_not_exist(lineno, test_list_path):
+ return
- if not self._full_test_list:
- tests = [test_list_path]
- else:
- tests = self._expand_tests(test_list_path)
+ if not self._full_test_list:
+ tests = [test_list_path]
+ else:
+ tests = self._expand_tests(test_list_path)
- self._add_tests(tests, expectations, test_list_path, lineno,
- modifiers, options, overrides_allowed)
+ modifiers = [o for o in options if o in self.MODIFIERS]
+ self._add_tests(tests, expectations, test_list_path, lineno,
+ modifiers, num_matches, options, overrides_allowed)
def _get_options_list(self, listString):
return [part.strip().lower() for part in listString.strip().split(' ')]
@@ -726,6 +637,65 @@ class TestExpectationsFile:
result.add(expectation)
return result
+ def _check_options(self, matcher, options, lineno, test_list_path):
+ match_result = self._check_syntax(matcher, options, lineno,
+ test_list_path)
+ self._check_semantics(options, lineno, test_list_path)
+ return match_result.num_matches
+
+ def _check_syntax(self, matcher, options, lineno, test_list_path):
+ match_result = matcher.match(options)
+ for error in match_result.errors:
+ self._add_error(lineno, error, test_list_path)
+ for warning in match_result.warnings:
+ self._log_non_fatal_error(lineno, warning, test_list_path)
+ return match_result
+
+ def _check_semantics(self, options, lineno, test_list_path):
+ has_wontfix = 'wontfix' in options
+ has_bug = False
+ for opt in options:
+ if opt.startswith('bug'):
+ has_bug = True
+ if re.match('bug\d+', opt):
+ self._add_error(lineno,
+ 'BUG\d+ is not allowed, must be one of '
+ 'BUGCR\d+, BUGWK\d+, BUGV8_\d+, '
+ 'or a non-numeric bug identifier.', test_list_path)
+
+ if not has_bug and not has_wontfix:
+ self._log_non_fatal_error(lineno, 'Test lacks BUG modifier.',
+ test_list_path)
+
+ if self._is_lint_mode and 'rebaseline' in options:
+ self._add_error(lineno,
+ 'REBASELINE should only be used for running rebaseline.py. '
+ 'Cannot be checked in.', test_list_path)
+
+ def _check_options_against_expectations(self, options, expectations,
+ lineno, test_list_path):
+ if 'slow' in options and TIMEOUT in expectations:
+ self._add_error(lineno,
+ 'A test can not be both SLOW and TIMEOUT. If it times out '
+ 'indefinitely, then it should be just TIMEOUT.', test_list_path)
+
+ def _check_path_does_not_exist(self, lineno, test_list_path):
+ full_path = self._fs.join(self._port.layout_tests_dir(),
+ test_list_path)
+ full_path = self._fs.normpath(full_path)
+ # WebKit's way of skipping tests is to add a -disabled suffix.
+ # So we should consider the path existing if the path or the
+ # -disabled version exists.
+ if (not self._port.path_exists(full_path)
+ and not self._port.path_exists(full_path + '-disabled')):
+ # Log a non fatal error here since you hit this case any
+ # time you update test_expectations.txt without syncing
+ # the LayoutTests directory
+ self._log_non_fatal_error(lineno, 'Path does not exist.',
+ test_list_path)
+ return True
+ return False
+
def _expand_tests(self, test_list_path):
"""Convert the test specification to an absolute, normalized
path and make sure directories end with the OS path separator."""
@@ -751,27 +721,30 @@ class TestExpectationsFile:
return result
def _add_tests(self, tests, expectations, test_list_path, lineno,
- modifiers, options, overrides_allowed):
+ modifiers, num_matches, options, overrides_allowed):
for test in tests:
- if self._already_seen_test(test, test_list_path, lineno,
- overrides_allowed):
+ if self._already_seen_better_match(test, test_list_path,
+ num_matches, lineno, overrides_allowed):
continue
self._clear_expectations_for_test(test, test_list_path)
- self._add_test(test, modifiers, expectations, options,
+ self._test_list_paths[test] = (self._fs.normpath(test_list_path),
+ num_matches, lineno)
+ self._add_test(test, modifiers, num_matches, expectations, options,
overrides_allowed)
- def _add_test(self, test, modifiers, expectations, options,
+ def _add_test(self, test, modifiers, num_matches, expectations, options,
overrides_allowed):
"""Sets the expected state for a given test.
This routine assumes the test has not been added before. If it has,
- use _ClearExpectationsForTest() to reset the state prior to
+ use _clear_expectations_for_test() to reset the state prior to
calling this.
Args:
test: test to add
modifiers: sequence of modifier keywords ('wontfix', 'slow', etc.)
+ num_matches: number of modifiers that matched the configuration
expectations: sequence of expectations (PASS, IMAGE, etc.)
options: sequence of keywords and bug identifiers.
overrides_allowed: whether we're parsing the regular expectations
@@ -828,32 +801,70 @@ class TestExpectationsFile:
if test in set_of_tests:
set_of_tests.remove(test)
- def _already_seen_test(self, test, test_list_path, lineno,
- allow_overrides):
- """Returns true if we've already seen a more precise path for this test
- than the test_list_path.
+ def _already_seen_better_match(self, test, test_list_path, num_matches,
+ lineno, overrides_allowed):
+ """Returns whether we've seen a better match already in the file.
+
+ Returns True if we've already seen a test_list_path that matches more of the test
+ than this path does
"""
+ # FIXME: See comment below about matching test configs and num_matches.
+
if not test in self._test_list_paths:
+ # We've never seen this test before.
return False
- prev_base_path = self._test_list_paths[test]
- if (prev_base_path == self._fs.normpath(test_list_path)):
- if (not allow_overrides or test in self._overridding_tests):
- if allow_overrides:
- expectation_source = "override"
- else:
- expectation_source = "expectation"
- self._add_error(lineno, 'Duplicate %s.' % expectation_source,
- test)
- return True
- else:
- # We have seen this path, but that's okay because its
- # in the overrides and the earlier path was in the
- # expectations.
- return False
+ prev_base_path, prev_num_matches, prev_lineno = self._test_list_paths[test]
+ base_path = self._fs.normpath(test_list_path)
+
+ if len(prev_base_path) > len(base_path):
+ # The previous path matched more of the test.
+ return True
+
+ if len(prev_base_path) < len(base_path):
+ # This path matches more of the test.
+ return False
+
+ if overrides_allowed and test not in self._overridding_tests:
+ # We have seen this path, but that's okay because it is
+ # in the overrides and the earlier path was in the
+ # expectations (not the overrides).
+ return False
+
+ # At this point we know we have seen a previous exact match on this
+ # base path, so we need to check the two sets of modifiers.
- # Check if we've already seen a more precise path.
- return prev_base_path.startswith(self._fs.normpath(test_list_path))
+ if overrides_allowed:
+ expectation_source = "override"
+ else:
+ expectation_source = "expectation"
+
+ # FIXME: This code was originally designed to allow lines that matched
+ # more modifiers to override lines that matched fewer modifiers.
+ # However, we currently view these as errors. If we decide to make
+ # this policy permanent, we can probably simplify this code
+ # and the ModifierMatcher code a fair amount.
+ #
+ # To use the "more modifiers wins" policy, change the "_add_error" lines for overrides
+ # to _log_non_fatal_error() and change the commented-out "return False".
+
+ if prev_num_matches == num_matches:
+ self._add_error(lineno,
+ 'Duplicate or ambiguous %s.' % expectation_source,
+ test)
+ return True
+
+ if prev_num_matches < num_matches:
+ self._add_error(lineno,
+ 'More specific entry on line %d overrides line %d' %
+ (lineno, prev_lineno), test_list_path)
+ # FIXME: return False if we want more specific to win.
+ return True
+
+ self._add_error(lineno,
+ 'More specific entry on line %d overrides line %d' %
+ (prev_lineno, lineno), test_list_path)
+ return True
def _add_error(self, lineno, msg, path):
"""Reports an error that will prevent running the tests. Does not
@@ -865,3 +876,188 @@ class TestExpectationsFile:
"""Reports an error that will not prevent running the tests. These are
still errors, but not bad enough to warrant breaking test running."""
self._non_fatal_errors.append('Line:%s %s %s' % (lineno, msg, path))
+
+
+class ModifierMatchResult(object):
+ def __init__(self, options):
+ self.num_matches = ModifierMatcher.NO_MATCH
+ self.options = options
+ self.errors = []
+ self.warnings = []
+ self.modifiers = []
+ self._matched_regexes = set()
+ self._matched_macros = set()
+
+
+class ModifierMatcher(object):
+
+ """
+ This class manages the interpretation of the "modifiers" for a given
+ line in the expectations file. Modifiers are the tokens that appear to the
+ left of the colon on a line. For example, "BUG1234", "DEBUG", and "WIN" are
+ all modifiers. This class gets what the valid modifiers are, and which
+ modifiers are allowed to exist together on a line, from the
+ TestConfiguration object that is passed in to the call.
+
+ This class detects *intra*-line errors like unknown modifiers, but
+ does not detect *inter*-line modifiers like duplicate expectations.
+
+ More importantly, this class is also used to determine if a given line
+ matches the port in question. Matches are ranked according to the number
+ of modifiers that match on a line. A line with no modifiers matches
+ everything and has a score of zero. A line with one modifier matches only
+ ports that have that modifier and gets a score of 1, and so one. Ports
+ that don't match at all get a score of -1.
+
+ Given two lines in a file that apply to the same test, if both expectations
+ match the current config, then the expectation is considered ambiguous,
+ even if one expectation matches more of the config than the other. For
+ example, in:
+
+ BUG1 RELEASE : foo.html = FAIL
+ BUG1 WIN RELEASE : foo.html = PASS
+ BUG2 WIN : bar.html = FAIL
+ BUG2 DEBUG : bar.html = PASS
+
+ lines 1 and 2 would produce an error on a Win XP Release bot (the scores
+ would be 1 and 2, respectively), and lines three and four would produce
+ a duplicate expectation on a Win Debug bot since both the 'win' and the
+ 'debug' expectations would apply (both had scores of 1).
+
+ In addition to the definitions of all of the modifiers, the class
+ supports "macros" that are expanded prior to interpretation, and "ignore
+ regexes" that can be used to skip over modifiers like the BUG* modifiers.
+ """
+ MACROS = {
+ 'mac-snowleopard': ['mac', 'snowleopard'],
+ 'mac-leopard': ['mac', 'leopard'],
+ 'win-xp': ['win', 'xp'],
+ 'win-vista': ['win', 'vista'],
+ 'win-7': ['win', 'win7'],
+ }
+
+ # We don't include the "none" modifier because it isn't actually legal.
+ REGEXES_TO_IGNORE = (['bug\w+'] +
+ TestExpectationsFile.MODIFIERS.keys()[:-1])
+ DUPLICATE_REGEXES_ALLOWED = ['bug\w+']
+
+ # Magic value returned when the options don't match.
+ NO_MATCH = -1
+
+ # FIXME: The code currently doesn't detect combinations of modifiers
+ # that are syntactically valid but semantically invalid, like
+ # 'MAC XP'. See ModifierMatchTest.test_invalid_combinations() in the
+ # _unittest.py file.
+
+ def __init__(self, test_config):
+ """Initialize a ModifierMatcher argument with the TestConfiguration it
+ should be matched against."""
+ self.test_config = test_config
+ self.allowed_configurations = test_config.all_test_configurations()
+ self.macros = self.MACROS
+
+ self.regexes_to_ignore = {}
+ for regex_str in self.REGEXES_TO_IGNORE:
+ self.regexes_to_ignore[regex_str] = re.compile(regex_str)
+
+ # Keep a set of all of the legal modifiers for quick checking.
+ self._all_modifiers = set()
+
+ # Keep a dict mapping values back to their categories.
+ self._categories_for_modifiers = {}
+ for config in self.allowed_configurations:
+ for category, modifier in config.items():
+ self._categories_for_modifiers[modifier] = category
+ self._all_modifiers.add(modifier)
+
+ def match(self, options):
+ """Checks a list of options against the config set in the constructor.
+ Options may be either actual modifier strings, "macro" strings
+ that get expanded to a list of modifiers, or strings that are allowed
+ to be ignored. All of the options must be passed in in lower case.
+
+ Returns the number of matching categories, or NO_MATCH (-1) if it
+ doesn't match or there were errors found. Matches are prioritized
+ by the number of matching categories, because the more specific
+ the options list, the more categories will match.
+
+ The results of the most recent match are available in the 'options',
+ 'modifiers', 'num_matches', 'errors', and 'warnings' properties.
+ """
+ result = ModifierMatchResult(options)
+ self._parse(result)
+ if result.errors:
+ return result
+ self._count_matches(result)
+ return result
+
+ def _parse(self, result):
+ # FIXME: Should we warn about lines having every value in a category?
+ for option in result.options:
+ self._parse_one(option, result)
+
+ def _parse_one(self, option, result):
+ if option in self._all_modifiers:
+ self._add_modifier(option, result)
+ elif option in self.macros:
+ self._expand_macro(option, result)
+ elif not self._matches_any_regex(option, result):
+ result.errors.append("Unrecognized option '%s'" % option)
+
+ def _add_modifier(self, option, result):
+ if option in result.modifiers:
+ result.errors.append("More than one '%s'" % option)
+ else:
+ result.modifiers.append(option)
+
+ def _expand_macro(self, macro, result):
+ if macro in result._matched_macros:
+ result.errors.append("More than one '%s'" % macro)
+ return
+
+ mods = []
+ for modifier in self.macros[macro]:
+ if modifier in result.options:
+ result.errors.append("Can't specify both modifier '%s' and "
+ "macro '%s'" % (modifier, macro))
+ else:
+ mods.append(modifier)
+ result._matched_macros.add(macro)
+ result.modifiers.extend(mods)
+
+ def _matches_any_regex(self, option, result):
+ for regex_str, pattern in self.regexes_to_ignore.iteritems():
+ if pattern.match(option):
+ self._handle_regex_match(regex_str, result)
+ return True
+ return False
+
+ def _handle_regex_match(self, regex_str, result):
+ if (regex_str in result._matched_regexes and
+ regex_str not in self.DUPLICATE_REGEXES_ALLOWED):
+ result.errors.append("More than one option matching '%s'" %
+ regex_str)
+ else:
+ result._matched_regexes.add(regex_str)
+
+ def _count_matches(self, result):
+ """Returns the number of modifiers that match the test config."""
+ categorized_modifiers = self._group_by_category(result.modifiers)
+ result.num_matches = 0
+ for category, modifier in self.test_config.items():
+ if category in categorized_modifiers:
+ if modifier in categorized_modifiers[category]:
+ result.num_matches += 1
+ else:
+ result.num_matches = self.NO_MATCH
+ return
+
+ def _group_by_category(self, modifiers):
+ # Returns a dict of category name -> list of modifiers.
+ modifiers_by_category = {}
+ for m in modifiers:
+ modifiers_by_category.setdefault(self._category(m), []).append(m)
+ return modifiers_by_category
+
+ def _category(self, modifier):
+ return self._categories_for_modifiers[modifier]
diff --git a/Tools/Scripts/webkitpy/layout_tests/layout_package/test_expectations_unittest.py b/Tools/Scripts/webkitpy/layout_tests/layout_package/test_expectations_unittest.py
index 8f9e5dd..05d805d 100644
--- a/Tools/Scripts/webkitpy/layout_tests/layout_package/test_expectations_unittest.py
+++ b/Tools/Scripts/webkitpy/layout_tests/layout_package/test_expectations_unittest.py
@@ -32,6 +32,7 @@
import unittest
from webkitpy.layout_tests import port
+from webkitpy.layout_tests.port import base
from webkitpy.layout_tests.layout_package.test_expectations import *
class FunctionsTest(unittest.TestCase):
@@ -78,8 +79,11 @@ class FunctionsTest(unittest.TestCase):
class Base(unittest.TestCase):
+ # Note that all of these tests are written assuming the configuration
+ # being tested is Windows XP, Release build.
+
def __init__(self, testFunc, setUp=None, tearDown=None, description=None):
- self._port = port.get('test', None)
+ self._port = port.get('test-win-xp', None)
self._fs = self._port._filesystem
self._exp = None
unittest.TestCase.__init__(self, testFunc)
@@ -101,16 +105,15 @@ BUG_TEST : failures/expected/text.html = TEXT
BUG_TEST WONTFIX SKIP : failures/expected/crash.html = CRASH
BUG_TEST REBASELINE : failures/expected/missing_image.html = MISSING
BUG_TEST WONTFIX : failures/expected/image_checksum.html = IMAGE
-BUG_TEST WONTFIX WIN : failures/expected/image.html = IMAGE
+BUG_TEST WONTFIX MAC : failures/expected/image.html = IMAGE
"""
- def parse_exp(self, expectations, overrides=None, is_lint_mode=False,
- is_debug_mode=False):
+ def parse_exp(self, expectations, overrides=None, is_lint_mode=False):
+ test_config = self._port.test_configuration()
self._exp = TestExpectations(self._port,
tests=self.get_basic_tests(),
expectations=expectations,
- test_platform_name=self._port.test_platform_name(),
- is_debug_mode=is_debug_mode,
+ test_config=test_config,
is_lint_mode=is_lint_mode,
overrides=overrides)
@@ -119,7 +122,7 @@ BUG_TEST WONTFIX WIN : failures/expected/image.html = IMAGE
set([result]))
-class TestExpectationsTest(Base):
+class BasicTests(Base):
def test_basic(self):
self.parse_exp(self.get_basic_expectations())
self.assert_exp('failures/expected/text.html', TEXT)
@@ -127,23 +130,14 @@ class TestExpectationsTest(Base):
self.assert_exp('passes/text.html', PASS)
self.assert_exp('failures/expected/image.html', PASS)
+
+class MiscTests(Base):
def test_multiple_results(self):
self.parse_exp('BUGX : failures/expected/text.html = TEXT CRASH')
self.assertEqual(self._exp.get_expectations(
self.get_test('failures/expected/text.html')),
set([TEXT, CRASH]))
- def test_precedence(self):
- # This tests handling precedence of specific lines over directories
- # and tests expectations covering entire directories.
- exp_str = """
-BUGX : failures/expected/text.html = TEXT
-BUGX WONTFIX : failures/expected = IMAGE
-"""
- self.parse_exp(exp_str)
- self.assert_exp('failures/expected/text.html', TEXT)
- self.assert_exp('failures/expected/crash.html', IMAGE)
-
def test_category_expectations(self):
# This test checks unknown tests are not present in the
# expectations and that known test part of a test category is
@@ -158,20 +152,6 @@ BUGX WONTFIX : failures/expected = IMAGE
unknown_test)
self.assert_exp('failures/expected/crash.html', IMAGE)
- def test_release_mode(self):
- self.parse_exp('BUGX DEBUG : failures/expected/text.html = TEXT',
- is_debug_mode=True)
- self.assert_exp('failures/expected/text.html', TEXT)
- self.parse_exp('BUGX RELEASE : failures/expected/text.html = TEXT',
- is_debug_mode=True)
- self.assert_exp('failures/expected/text.html', PASS)
- self.parse_exp('BUGX DEBUG : failures/expected/text.html = TEXT',
- is_debug_mode=False)
- self.assert_exp('failures/expected/text.html', PASS)
- self.parse_exp('BUGX RELEASE : failures/expected/text.html = TEXT',
- is_debug_mode=False)
- self.assert_exp('failures/expected/text.html', TEXT)
-
def test_get_options(self):
self.parse_exp(self.get_basic_expectations())
self.assertEqual(self._exp.get_options(
@@ -216,7 +196,7 @@ SKIP : failures/expected/image.html""")
self.assertFalse(True, "ParseError wasn't raised")
except ParseError, e:
self.assertTrue(e.fatal)
- exp_errors = [u'Line:1 Invalid modifier for test: foo failures/expected/text.html',
+ exp_errors = [u"Line:1 Unrecognized option 'foo' failures/expected/text.html",
u"Line:2 Missing expectations. [' failures/expected/image.html']"]
self.assertEqual(str(e), '\n'.join(map(str, exp_errors)))
self.assertEqual(e.errors, exp_errors)
@@ -232,77 +212,167 @@ SKIP : failures/expected/image.html""")
self.assertEqual(str(e), '\n'.join(map(str, exp_errors)))
self.assertEqual(e.errors, exp_errors)
- def test_syntax_missing_expectation(self):
+ def test_overrides(self):
+ self.parse_exp("BUG_EXP: failures/expected/text.html = TEXT",
+ "BUG_OVERRIDE : failures/expected/text.html = IMAGE")
+ self.assert_exp('failures/expected/text.html', IMAGE)
+
+ def test_overrides__duplicate(self):
+ self.assertRaises(ParseError, self.parse_exp,
+ "BUG_EXP: failures/expected/text.html = TEXT",
+ """
+BUG_OVERRIDE : failures/expected/text.html = IMAGE
+BUG_OVERRIDE : failures/expected/text.html = CRASH
+""")
+
+ def test_pixel_tests_flag(self):
+ def match(test, result, pixel_tests_enabled):
+ return self._exp.matches_an_expected_result(
+ self.get_test(test), result, pixel_tests_enabled)
+
+ self.parse_exp(self.get_basic_expectations())
+ self.assertTrue(match('failures/expected/text.html', TEXT, True))
+ self.assertTrue(match('failures/expected/text.html', TEXT, False))
+ self.assertFalse(match('failures/expected/text.html', CRASH, True))
+ self.assertFalse(match('failures/expected/text.html', CRASH, False))
+ self.assertTrue(match('failures/expected/image_checksum.html', IMAGE,
+ True))
+ self.assertTrue(match('failures/expected/image_checksum.html', PASS,
+ False))
+ self.assertTrue(match('failures/expected/crash.html', SKIP, False))
+ self.assertTrue(match('passes/text.html', PASS, False))
+
+ def test_more_specific_override_resets_skip(self):
+ self.parse_exp("BUGX SKIP : failures/expected = TEXT\n"
+ "BUGX : failures/expected/text.html = IMAGE\n")
+ self.assert_exp('failures/expected/text.html', IMAGE)
+ self.assertFalse(self._port._filesystem.join(self._port.layout_tests_dir(),
+ 'failures/expected/text.html') in
+ self._exp.get_tests_with_result_type(SKIP))
+
+class ExpectationSyntaxTests(Base):
+ def test_missing_expectation(self):
# This is missing the expectation.
self.assertRaises(ParseError, self.parse_exp,
- 'BUG_TEST: failures/expected/text.html',
- is_debug_mode=True)
+ 'BUG_TEST: failures/expected/text.html')
- def test_syntax_invalid_option(self):
+ def test_missing_colon(self):
+ # This is missing the modifiers and the ':'
self.assertRaises(ParseError, self.parse_exp,
- 'BUG_TEST FOO: failures/expected/text.html = PASS')
+ 'failures/expected/text.html = TEXT')
- def test_syntax_invalid_expectation(self):
- # This is missing the expectation.
+ def disabled_test_too_many_colons(self):
+ # FIXME: Enable this test and fix the underlying bug.
+ self.assertRaises(ParseError, self.parse_exp,
+ 'BUG_TEST: failures/expected/text.html = PASS :')
+
+ def test_too_many_equals_signs(self):
self.assertRaises(ParseError, self.parse_exp,
- 'BUG_TEST: failures/expected/text.html = FOO')
+ 'BUG_TEST: failures/expected/text.html = TEXT = IMAGE')
+
+ def test_unrecognized_expectation(self):
+ self.assertRaises(ParseError, self.parse_exp,
+ 'BUG_TEST: failures/expected/text.html = UNKNOWN')
+
+ def test_macro(self):
+ exp_str = """
+BUG_TEST WIN-XP : failures/expected/text.html = TEXT
+"""
+ self.parse_exp(exp_str)
+ self.assert_exp('failures/expected/text.html', TEXT)
+
+
+class SemanticTests(Base):
+ def test_bug_format(self):
+ self.assertRaises(ParseError, self.parse_exp, 'BUG1234 : failures/expected/text.html = TEXT')
- def test_syntax_missing_bugid(self):
+ def test_missing_bugid(self):
# This should log a non-fatal error.
self.parse_exp('SLOW : failures/expected/text.html = TEXT')
self.assertEqual(
len(self._exp._expected_failures.get_non_fatal_errors()), 1)
- def test_semantic_slow_and_timeout(self):
+ def test_slow_and_timeout(self):
# A test cannot be SLOW and expected to TIMEOUT.
self.assertRaises(ParseError, self.parse_exp,
'BUG_TEST SLOW : failures/expected/timeout.html = TIMEOUT')
- def test_semantic_rebaseline(self):
+ def test_rebaseline(self):
# Can't lint a file w/ 'REBASELINE' in it.
self.assertRaises(ParseError, self.parse_exp,
'BUG_TEST REBASELINE : failures/expected/text.html = TEXT',
is_lint_mode=True)
- def test_semantic_duplicates(self):
+ def test_duplicates(self):
self.assertRaises(ParseError, self.parse_exp, """
-BUG_TEST : failures/expected/text.html = TEXT
-BUG_TEST : failures/expected/text.html = IMAGE""")
+BUG_EXP : failures/expected/text.html = TEXT
+BUG_EXP : failures/expected/text.html = IMAGE""")
self.assertRaises(ParseError, self.parse_exp,
- self.get_basic_expectations(), """
-BUG_TEST : failures/expected/text.html = TEXT
-BUG_TEST : failures/expected/text.html = IMAGE""")
+ self.get_basic_expectations(), overrides="""
+BUG_OVERRIDE : failures/expected/text.html = TEXT
+BUG_OVERRIDE : failures/expected/text.html = IMAGE""", )
- def test_semantic_missing_file(self):
+ def test_missing_file(self):
# This should log a non-fatal error.
self.parse_exp('BUG_TEST : missing_file.html = TEXT')
self.assertEqual(
len(self._exp._expected_failures.get_non_fatal_errors()), 1)
- def test_overrides(self):
- self.parse_exp(self.get_basic_expectations(), """
-BUG_OVERRIDE : failures/expected/text.html = IMAGE""")
- self.assert_exp('failures/expected/text.html', IMAGE)
+class PrecedenceTests(Base):
+ def test_file_over_directory(self):
+ # This tests handling precedence of specific lines over directories
+ # and tests expectations covering entire directories.
+ exp_str = """
+BUGX : failures/expected/text.html = TEXT
+BUGX WONTFIX : failures/expected = IMAGE
+"""
+ self.parse_exp(exp_str)
+ self.assert_exp('failures/expected/text.html', TEXT)
+ self.assert_exp('failures/expected/crash.html', IMAGE)
- def test_matches_an_expected_result(self):
+ exp_str = """
+BUGX WONTFIX : failures/expected = IMAGE
+BUGX : failures/expected/text.html = TEXT
+"""
+ self.parse_exp(exp_str)
+ self.assert_exp('failures/expected/text.html', TEXT)
+ self.assert_exp('failures/expected/crash.html', IMAGE)
- def match(test, result, pixel_tests_enabled):
- return self._exp.matches_an_expected_result(
- self.get_test(test), result, pixel_tests_enabled)
+ def test_ambiguous(self):
+ self.assertRaises(ParseError, self.parse_exp, """
+BUG_TEST RELEASE : passes/text.html = PASS
+BUG_TEST WIN : passes/text.html = FAIL
+""")
- self.parse_exp(self.get_basic_expectations())
- self.assertTrue(match('failures/expected/text.html', TEXT, True))
- self.assertTrue(match('failures/expected/text.html', TEXT, False))
- self.assertFalse(match('failures/expected/text.html', CRASH, True))
- self.assertFalse(match('failures/expected/text.html', CRASH, False))
- self.assertTrue(match('failures/expected/image_checksum.html', IMAGE,
- True))
- self.assertTrue(match('failures/expected/image_checksum.html', PASS,
- False))
- self.assertTrue(match('failures/expected/crash.html', SKIP, False))
- self.assertTrue(match('passes/text.html', PASS, False))
+ def test_more_modifiers(self):
+ exp_str = """
+BUG_TEST RELEASE : passes/text.html = PASS
+BUG_TEST WIN RELEASE : passes/text.html = TEXT
+"""
+ self.assertRaises(ParseError, self.parse_exp, exp_str)
+
+ def test_order_in_file(self):
+ exp_str = """
+BUG_TEST WIN RELEASE : passes/text.html = TEXT
+BUG_TEST RELEASE : passes/text.html = PASS
+"""
+ self.assertRaises(ParseError, self.parse_exp, exp_str)
+
+ def test_version_overrides(self):
+ exp_str = """
+BUG_TEST WIN : passes/text.html = PASS
+BUG_TEST WIN XP : passes/text.html = TEXT
+"""
+ self.assertRaises(ParseError, self.parse_exp, exp_str)
+
+ def test_macro_overrides(self):
+ exp_str = """
+BUG_TEST WIN : passes/text.html = PASS
+BUG_TEST WIN-XP : passes/text.html = TEXT
+"""
+ self.assertRaises(ParseError, self.parse_exp, exp_str)
class RebaseliningTest(Base):
@@ -327,7 +397,8 @@ BUG_TEST REBASELINE : failures/expected/text.html = TEXT
def test_remove_expand(self):
self.assertRemove('mac',
'BUGX REBASELINE : failures/expected/text.html = TEXT\n',
- 'BUGX REBASELINE WIN : failures/expected/text.html = TEXT\n')
+ 'BUGX REBASELINE WIN : failures/expected/text.html = TEXT\n'
+ 'BUGX REBASELINE WIN-XP : failures/expected/text.html = TEXT\n')
def test_remove_mac_win(self):
self.assertRemove('mac',
@@ -345,5 +416,85 @@ BUG_TEST REBASELINE : failures/expected/text.html = TEXT
'\n\n')
+class ModifierTests(unittest.TestCase):
+ def setUp(self):
+ port_obj = port.get('test-win-xp', None)
+ self.config = port_obj.test_configuration()
+ self.matcher = ModifierMatcher(self.config)
+
+ def match(self, modifiers, expected_num_matches=-1, values=None, num_errors=0):
+ matcher = self.matcher
+ if values:
+ matcher = ModifierMatcher(self.FakeTestConfiguration(values))
+ match_result = matcher.match(modifiers)
+ self.assertEqual(len(match_result.warnings), 0)
+ self.assertEqual(len(match_result.errors), num_errors)
+ self.assertEqual(match_result.num_matches, expected_num_matches,
+ 'match(%s, %s) returned -> %d, expected %d' %
+ (modifiers, str(self.config.values()),
+ match_result.num_matches, expected_num_matches))
+
+ def test_bad_match_modifier(self):
+ self.match(['foo'], num_errors=1)
+
+ def test_none(self):
+ self.match([], 0)
+
+ def test_one(self):
+ self.match(['xp'], 1)
+ self.match(['win'], 1)
+ self.match(['release'], 1)
+ self.match(['cpu'], 1)
+ self.match(['x86'], 1)
+ self.match(['leopard'], -1)
+ self.match(['gpu'], -1)
+ self.match(['debug'], -1)
+
+ def test_two(self):
+ self.match(['xp', 'release'], 2)
+ self.match(['win7', 'release'], -1)
+ self.match(['win7', 'xp'], 1)
+
+ def test_three(self):
+ self.match(['win7', 'xp', 'release'], 2)
+ self.match(['xp', 'debug', 'x86'], -1)
+ self.match(['xp', 'release', 'x86'], 3)
+ self.match(['xp', 'cpu', 'release'], 3)
+
+ def test_four(self):
+ self.match(['xp', 'release', 'cpu', 'x86'], 4)
+ self.match(['win7', 'xp', 'release', 'cpu'], 3)
+ self.match(['win7', 'xp', 'debug', 'cpu'], -1)
+
+ def test_case_insensitivity(self):
+ self.match(['Win'], num_errors=1)
+ self.match(['WIN'], num_errors=1)
+ self.match(['win'], 1)
+
+ def test_duplicates(self):
+ self.match(['release', 'release'], num_errors=1)
+ self.match(['win-xp', 'xp'], num_errors=1)
+ self.match(['win-xp', 'win-xp'], num_errors=1)
+ self.match(['xp', 'release', 'xp', 'release'], num_errors=2)
+ self.match(['rebaseline', 'rebaseline'], num_errors=1)
+
+ def test_unknown_option(self):
+ self.match(['vms'], num_errors=1)
+
+ def test_duplicate_bugs(self):
+ # BUG* regexes can appear multiple times.
+ self.match(['bugfoo', 'bugbar'], 0)
+
+ def test_invalid_combinations(self):
+ # FIXME: This should probably raise an error instead of NO_MATCH.
+ self.match(['mac', 'xp'], num_errors=0)
+
+ def test_regexes_are_ignored(self):
+ self.match(['bug123xy', 'rebaseline', 'wontfix', 'slow', 'skip'], 0)
+
+ def test_none_is_invalid(self):
+ self.match(['none'], num_errors=1)
+
+
if __name__ == '__main__':
unittest.main()
diff --git a/Tools/Scripts/webkitpy/layout_tests/layout_package/test_input.py b/Tools/Scripts/webkitpy/layout_tests/layout_package/test_input.py
index 4b027c0..0aed1dd 100644
--- a/Tools/Scripts/webkitpy/layout_tests/layout_package/test_input.py
+++ b/Tools/Scripts/webkitpy/layout_tests/layout_package/test_input.py
@@ -41,7 +41,3 @@ class TestInput:
# FIXME: filename should really be test_name as a relative path.
self.filename = filename
self.timeout = timeout
- # The image_hash is used to avoid doing an image dump if the
- # checksums match. The image_hash is set later, and only if it is needed
- # for the test.
- self.image_hash = None
diff --git a/Tools/Scripts/webkitpy/layout_tests/layout_package/test_runner.py b/Tools/Scripts/webkitpy/layout_tests/layout_package/test_runner.py
index 6c07850..e3bd4ad 100644
--- a/Tools/Scripts/webkitpy/layout_tests/layout_package/test_runner.py
+++ b/Tools/Scripts/webkitpy/layout_tests/layout_package/test_runner.py
@@ -214,21 +214,13 @@ class TestRunner:
def lint(self):
lint_failed = False
-
- # Creating the expecations for each platform/configuration pair does
- # all the test list parsing and ensures it's correct syntax (e.g. no
- # dupes).
- for platform_name in self._port.test_platform_names():
- try:
- self.parse_expectations(platform_name, is_debug_mode=True)
- except test_expectations.ParseError:
- lint_failed = True
+ for test_configuration in self._port.all_test_configurations():
try:
- self.parse_expectations(platform_name, is_debug_mode=False)
+ self.lint_expectations(test_configuration)
except test_expectations.ParseError:
lint_failed = True
+ self._printer.write("")
- self._printer.write("")
if lint_failed:
_log.error("Lint failed.")
return -1
@@ -236,22 +228,28 @@ class TestRunner:
_log.info("Lint succeeded.")
return 0
- def parse_expectations(self, test_platform_name, is_debug_mode):
+ def lint_expectations(self, config):
+ port = self._port
+ test_expectations.TestExpectations(
+ port,
+ None,
+ port.test_expectations(),
+ config,
+ self._options.lint_test_files,
+ port.test_expectations_overrides())
+
+ def parse_expectations(self):
"""Parse the expectations from the test_list files and return a data
structure holding them. Throws an error if the test_list files have
invalid syntax."""
- if self._options.lint_test_files:
- test_files = None
- else:
- test_files = self._test_files
-
- expectations_str = self._port.test_expectations()
- overrides_str = self._port.test_expectations_overrides()
+ port = self._port
self._expectations = test_expectations.TestExpectations(
- self._port, test_files, expectations_str, test_platform_name,
- is_debug_mode, self._options.lint_test_files,
- overrides=overrides_str)
- return self._expectations
+ port,
+ self._test_files,
+ port.test_expectations(),
+ port.test_configuration(),
+ self._options.lint_test_files,
+ port.test_expectations_overrides())
# FIXME: This method is way too long and needs to be broken into pieces.
def prepare_lists_and_print_output(self):
@@ -358,9 +356,7 @@ class TestRunner:
self._test_files_list = files + skip_chunk_list
self._test_files = set(self._test_files_list)
- self._expectations = self.parse_expectations(
- self._port.test_platform_name(),
- self._options.configuration == 'Debug')
+ self.parse_expectations()
self._test_files = set(files)
self._test_files_list = files
@@ -691,6 +687,8 @@ class TestRunner:
self._expectations, result_summary, retry_summary)
self._printer.print_unexpected_results(unexpected_results)
+ # FIXME: remove record_results. It's just used for testing. There's no need
+ # for it to be a commandline argument.
if (self._options.record_results and not self._options.dry_run and
not interrupted):
# Write the same data to log files and upload generated JSON files
@@ -731,28 +729,31 @@ class TestRunner:
except Queue.Empty:
return
- expected = self._expectations.matches_an_expected_result(
- result.filename, result.type, self._options.pixel_tests)
- result_summary.add(result, expected)
- exp_str = self._expectations.get_expectations_string(
- result.filename)
- got_str = self._expectations.expectation_to_string(result.type)
- self._printer.print_test_result(result, expected, exp_str, got_str)
- self._printer.print_progress(result_summary, self._retrying,
- self._test_files_list)
-
- def interrupt_if_at_failure_limit(limit, count, message):
- if limit and count >= limit:
- raise TestRunInterruptedException(message % count)
-
- interrupt_if_at_failure_limit(
- self._options.exit_after_n_failures,
- result_summary.unexpected_failures,
- "Aborting run since %d failures were reached")
- interrupt_if_at_failure_limit(
- self._options.exit_after_n_crashes_or_timeouts,
- result_summary.unexpected_crashes_or_timeouts,
- "Aborting run since %d crashes or timeouts were reached")
+ self._update_summary_with_result(result_summary, result)
+
+ def _update_summary_with_result(self, result_summary, result):
+ expected = self._expectations.matches_an_expected_result(
+ result.filename, result.type, self._options.pixel_tests)
+ result_summary.add(result, expected)
+ exp_str = self._expectations.get_expectations_string(
+ result.filename)
+ got_str = self._expectations.expectation_to_string(result.type)
+ self._printer.print_test_result(result, expected, exp_str, got_str)
+ self._printer.print_progress(result_summary, self._retrying,
+ self._test_files_list)
+
+ def interrupt_if_at_failure_limit(limit, count, message):
+ if limit and count >= limit:
+ raise TestRunInterruptedException(message % count)
+
+ interrupt_if_at_failure_limit(
+ self._options.exit_after_n_failures,
+ result_summary.unexpected_failures,
+ "Aborting run since %d failures were reached")
+ interrupt_if_at_failure_limit(
+ self._options.exit_after_n_crashes_or_timeouts,
+ result_summary.unexpected_crashes_or_timeouts,
+ "Aborting run since %d crashes or timeouts were reached")
def _clobber_old_results(self):
# Just clobber the actual test results directories since the other
@@ -789,7 +790,7 @@ class TestRunner:
return failed_results
def _upload_json_files(self, unexpected_results, result_summary,
- individual_test_timings):
+ individual_test_timings):
"""Writes the results of the test run as JSON files into the results
dir and upload the files to the appengine server.
@@ -825,18 +826,13 @@ class TestRunner:
self._options.build_number, self._options.results_directory,
BUILDER_BASE_URL, individual_test_timings,
self._expectations, result_summary, self._test_files_list,
- not self._options.upload_full_results,
self._options.test_results_server,
"layout-tests",
self._options.master_name)
_log.debug("Finished writing JSON files.")
- json_files = ["expectations.json"]
- if self._options.upload_full_results:
- json_files.append("results.json")
- else:
- json_files.append("incremental_results.json")
+ json_files = ["expectations.json", "incremental_results.json"]
generator.upload_json_files(json_files)
@@ -844,6 +840,7 @@ class TestRunner:
"""Prints the configuration for the test run."""
p = self._printer
p.print_config("Using port '%s'" % self._port.name())
+ p.print_config("Test configuration: %s" % self._port.test_configuration())
p.print_config("Placing test results in %s" %
self._options.results_directory)
if self._options.new_baseline:
diff --git a/Tools/Scripts/webkitpy/layout_tests/layout_package/test_runner2.py b/Tools/Scripts/webkitpy/layout_tests/layout_package/test_runner2.py
new file mode 100644
index 0000000..f097b83
--- /dev/null
+++ b/Tools/Scripts/webkitpy/layout_tests/layout_package/test_runner2.py
@@ -0,0 +1,129 @@
+#!/usr/bin/env python
+# Copyright (C) 2011 Google Inc. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+# * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+"""
+The TestRunner2 package is an alternate implementation of the TestRunner
+class that uses the manager_worker_broker module to send sets of tests to
+workers and receive their completion messages accordingly.
+"""
+
+import logging
+
+
+from webkitpy.layout_tests.layout_package import manager_worker_broker
+from webkitpy.layout_tests.layout_package import test_runner
+from webkitpy.layout_tests.layout_package import worker
+
+_log = logging.getLogger(__name__)
+
+
+class TestRunner2(test_runner.TestRunner):
+ def __init__(self, port, options, printer):
+ test_runner.TestRunner.__init__(self, port, options, printer)
+ self._all_results = []
+ self._group_stats = {}
+ self._current_result_summary = None
+ self._done = False
+
+ def is_done(self):
+ return self._done
+
+ def name(self):
+ return 'TestRunner2'
+
+ def _run_tests(self, file_list, result_summary):
+ """Runs the tests in the file_list.
+
+ Return: A tuple (keyboard_interrupted, thread_timings, test_timings,
+ individual_test_timings)
+ keyboard_interrupted is whether someone typed Ctrl^C
+ thread_timings is a list of dicts with the total runtime
+ of each thread with 'name', 'num_tests', 'total_time' properties
+ test_timings is a list of timings for each sharded subdirectory
+ of the form [time, directory_name, num_tests]
+ individual_test_timings is a list of run times for each test
+ in the form {filename:filename, test_run_time:test_run_time}
+ result_summary: summary object to populate with the results
+ """
+ self._current_result_summary = result_summary
+
+ # FIXME: shard properly.
+
+ # FIXME: should shard_tests return a list of objects rather than tuples?
+ test_lists = self._shard_tests(file_list, False)
+
+ manager_connection = manager_worker_broker.get(self._port, self._options, self, worker.Worker)
+
+ # FIXME: start all of the workers.
+ manager_connection.start_worker(0)
+
+ for test_list in test_lists:
+ manager_connection.post_message('test_list', test_list[0], test_list[1])
+
+ manager_connection.post_message('stop')
+
+ keyboard_interrupted = False
+ interrupted = False
+ if not self._options.dry_run:
+ while not self._check_if_done():
+ manager_connection.run_message_loop(delay_secs=1.0)
+
+ # FIXME: implement stats.
+ thread_timings = []
+
+ # FIXME: should this be a class instead of a tuple?
+ return (keyboard_interrupted, interrupted, thread_timings,
+ self._group_stats, self._all_results)
+
+ def _check_if_done(self):
+ """Returns true iff all the workers have either completed or wedged."""
+ # FIXME: implement to check for wedged workers.
+ return self._done
+
+ def handle_started_test(self, src, test_info, hang_timeout):
+ # FIXME: implement
+ pass
+
+ def handle_done(self, src):
+ # FIXME: implement properly to handle multiple workers.
+ self._done = True
+ pass
+
+ def handle_exception(self, src, exception_info):
+ raise exception_info
+
+ def handle_finished_list(self, src, list_name, num_tests, elapsed_time):
+ # FIXME: update stats
+ pass
+
+ def handle_finished_test(self, src, result, elapsed_time):
+ self._update_summary_with_result(self._current_result_summary, result)
+
+ # FIXME: update stats.
+ self._all_results.append(result)
diff --git a/Tools/Scripts/webkitpy/layout_tests/layout_package/worker.py b/Tools/Scripts/webkitpy/layout_tests/layout_package/worker.py
new file mode 100644
index 0000000..47d4fbd
--- /dev/null
+++ b/Tools/Scripts/webkitpy/layout_tests/layout_package/worker.py
@@ -0,0 +1,104 @@
+# Copyright (C) 2011 Google Inc. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+# * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+"""Handle messages from the TestRunner and execute actual tests."""
+
+import logging
+import sys
+import time
+
+from webkitpy.common.system import stack_utils
+
+from webkitpy.layout_tests.layout_package import manager_worker_broker
+from webkitpy.layout_tests.layout_package import test_results
+
+
+_log = logging.getLogger(__name__)
+
+
+class Worker(manager_worker_broker.AbstractWorker):
+ def __init__(self, worker_connection, worker_number, options):
+ self._worker_connection = worker_connection
+ self._worker_number = worker_number
+ self._options = options
+ self._name = 'worker/%d' % worker_number
+ self._done = False
+ self._port = None
+
+ def _deferred_init(self, port):
+ self._port = port
+
+ def is_done(self):
+ return self._done
+
+ def name(self):
+ return self._name
+
+ def run(self, port):
+ self._deferred_init(port)
+
+ _log.debug("%s starting" % self._name)
+
+ # FIXME: need to add in error handling, better logging.
+ self._worker_connection.run_message_loop()
+ self._worker_connection.post_message('done')
+
+ def handle_test_list(self, src, list_name, test_list):
+ # FIXME: check to see if we need to get the http lock.
+
+ start_time = time.time()
+ num_tests = 0
+ for test_input in test_list:
+ self._run_test(test_input)
+ num_tests += 1
+ self._worker_connection.yield_to_broker()
+
+ elapsed_time = time.time() - start_time
+ self._worker_connection.post_message('finished_list', list_name, num_tests, elapsed_time)
+
+ # FIXME: release the lock if necessary
+
+ def handle_stop(self, src):
+ self._done = True
+
+ def _run_test(self, test_input):
+
+ # FIXME: get real timeout value from SingleTestRunner
+ test_timeout_sec = int(test_input.timeout) / 1000
+ start = time.time()
+ self._worker_connection.post_message('started_test', test_input, test_timeout_sec)
+
+ # FIXME: actually run the test.
+ result = test_results.TestResult(test_input.filename, failures=[],
+ test_run_time=0, total_time_for_all_diffs=0, time_for_diffs={})
+
+ elapsed_time = time.time() - start
+
+ # FIXME: update stats, check for failures.
+
+ self._worker_connection.post_message('finished_test', result, elapsed_time)
diff --git a/Tools/Scripts/webkitpy/layout_tests/port/base.py b/Tools/Scripts/webkitpy/layout_tests/port/base.py
index 6e5fabc..5ff4bff 100644
--- a/Tools/Scripts/webkitpy/layout_tests/port/base.py
+++ b/Tools/Scripts/webkitpy/layout_tests/port/base.py
@@ -121,15 +121,18 @@ class Port(object):
# certainly won't be available, so it's a good test to keep us
# from erroring out later.
self._pretty_patch_available = self._filesystem.exists(self._pretty_patch_path)
- self.set_option_default('configuration', None)
- if self._options.configuration is None:
+ if not hasattr(self._options, 'configuration') or self._options.configuration is None:
self._options.configuration = self.default_configuration()
+ self._test_configuration = None
def default_child_processes(self):
"""Return the number of DumpRenderTree instances to use for this
port."""
return self._executive.cpu_count()
+ def default_worker_model(self):
+ return 'old-threads'
+
def baseline_path(self):
"""Return the absolute path to the directory to store new baselines
in for this port."""
@@ -315,7 +318,7 @@ class Port(object):
path = self.expected_filename(test, '.checksum')
if not self.path_exists(path):
return None
- return self._filesystem.read_text_file(path)
+ return self._filesystem.read_binary_file(path)
def expected_image(self, test):
"""Returns the image we expect the test to produce."""
@@ -393,7 +396,7 @@ class Port(object):
driver = self.create_driver(0)
return driver.cmd_line()
- def update_baseline(self, path, data, encoding):
+ def update_baseline(self, path, data):
"""Updates the baseline for a test.
Args:
@@ -401,14 +404,8 @@ class Port(object):
the test. This function is used to update either generic or
platform-specific baselines, but we can't infer which here.
data: contents of the baseline.
- encoding: file encoding to use for the baseline.
"""
- # FIXME: remove the encoding parameter in favor of text/binary
- # functions.
- if encoding is None:
- self._filesystem.write_binary_file(path, data)
- else:
- self._filesystem.write_text_file(path, data)
+ self._filesystem.write_binary_file(path, data)
def uri_to_test_name(self, uri):
"""Return the base layout test name for a given URI.
@@ -465,6 +462,15 @@ class Port(object):
may be different (e.g., 'win-xp' instead of 'chromium-win-xp'."""
return self._name
+ def graphics_type(self):
+ """Returns whether the port uses accelerated graphics ('gpu') or not
+ ('cpu')."""
+ return 'cpu'
+
+ def real_name(self):
+ """Returns the actual name of the port, not the delegate's."""
+ return self.name()
+
def get_option(self, name, default_value=None):
# FIXME: Eventually we should not have to do a test for
# hasattr(), and we should be able to just do
@@ -496,9 +502,16 @@ class Port(object):
"""Relative unix-style path for a filename under the LayoutTests
directory. Filenames outside the LayoutTests directory should raise
an error."""
+ # FIXME: On Windows, does this return test_names with forward slashes,
+ # or windows-style relative paths?
assert filename.startswith(self.layout_tests_dir()), "%s did not start with %s" % (filename, self.layout_tests_dir())
return filename[len(self.layout_tests_dir()) + 1:]
+ def abspath_for_test(self, test_name):
+ """Returns the full path to the file for a given test name. This is the
+ inverse of relative_test_filename()."""
+ return self._filesystem.normpath(self._filesystem.join(self.layout_tests_dir(), test_name))
+
def results_directory(self):
"""Absolute path to the place to store the test results."""
raise NotImplementedError('Port.results_directory')
@@ -577,12 +590,25 @@ class Port(object):
if self._http_lock:
self._http_lock.cleanup_http_lock()
+ #
+ # TEST EXPECTATION-RELATED METHODS
+ #
+
+ def test_configuration(self):
+ """Returns the current TestConfiguration for the port."""
+ if not self._test_configuration:
+ self._test_configuration = TestConfiguration(self)
+ return self._test_configuration
+
+ def all_test_configurations(self):
+ return self.test_configuration().all_test_configurations()
+
def test_expectations(self):
"""Returns the test expectations for this port.
Basically this string should contain the equivalent of a
test_expectations file. See test_expectations.py for more details."""
- raise NotImplementedError('Port.test_expectations')
+ return self._filesystem.read_text_file(self.path_to_test_expectations_file())
def test_expectations_overrides(self):
"""Returns an optional set of overrides for the test_expectations.
@@ -593,18 +619,6 @@ class Port(object):
sync up the two repos."""
return None
- def test_base_platform_names(self):
- """Return a list of the 'base' platforms on your port. The base
- platforms represent different architectures, operating systems,
- or implementations (as opposed to different versions of a single
- platform). For example, 'mac' and 'win' might be different base
- platforms, wherease 'mac-tiger' and 'mac-leopard' might be
- different platforms. This routine is used by the rebaselining tool
- and the dashboards, and the strings correspond to the identifiers
- in your test expectations (*not* necessarily the platform names
- themselves)."""
- raise NotImplementedError('Port.base_test_platforms')
-
def test_platform_name(self):
"""Returns the string that corresponds to the given platform name
in the test expectations. This may be the same as name(), or it
@@ -810,6 +824,48 @@ class Port(object):
platform)
+class DriverInput(object):
+ """Holds the input parameters for a driver."""
+
+ def __init__(self, filename, timeout, image_hash):
+ """Initializes a DriverInput object.
+
+ Args:
+ filename: Full path to the test.
+ timeout: Timeout in msecs the driver should use while running the test
+ image_hash: A image checksum which is used to avoid doing an image dump if
+ the checksums match.
+ """
+ self.filename = filename
+ self.timeout = timeout
+ self.image_hash = image_hash
+
+
+class DriverOutput(object):
+ """Groups information about a output from driver for easy passing of data."""
+
+ def __init__(self, text, image, image_hash,
+ crash=False, test_time=None, timeout=False, error=''):
+ """Initializes a TestOutput object.
+
+ Args:
+ text: a text output
+ image: an image output
+ image_hash: a string containing the checksum of the image
+ crash: a boolean indicating whether the driver crashed on the test
+ test_time: a time which the test has taken
+ timeout: a boolean indicating whehter the test timed out
+ error: any unexpected or additional (or error) text output
+ """
+ self.text = text
+ self.image = image
+ self.image_hash = image_hash
+ self.crash = crash
+ self.test_time = test_time
+ self.timeout = timeout
+ self.error = error
+
+
class Driver:
"""Abstract interface for the DumpRenderTree interface."""
@@ -824,7 +880,7 @@ class Driver:
"""
raise NotImplementedError('Driver.__init__')
- def run_test(self, test_input):
+ def run_test(self, driver_input):
"""Run a single test and return the results.
Note that it is okay if a test times out or crashes and leaves
@@ -832,9 +888,9 @@ class Driver:
are responsible for cleaning up and ensuring things are okay.
Args:
- test_input: a TestInput object
+ driver_input: a DriverInput object
- Returns a TestOutput object.
+ Returns a DriverOutput object.
"""
raise NotImplementedError('Driver.run_test')
@@ -863,3 +919,68 @@ class Driver:
def stop(self):
raise NotImplementedError('Driver.stop')
+
+
+class TestConfiguration(object):
+ def __init__(self, port=None, os=None, version=None, architecture=None,
+ build_type=None, graphics_type=None):
+
+ # FIXME: We can get the O/S and version from test_platform_name()
+ # and version() for now, but those should go away and be cleaned up
+ # with more generic methods like operation_system() and os_version()
+ # or something. Note that we need to strip the leading '-' off the
+ # version string if it is present.
+ if port:
+ port_version = port.version()
+ self.os = os or port.test_platform_name().replace(port_version, '')
+ self.version = version or port_version[1:]
+ self.architecture = architecture or 'x86'
+ self.build_type = build_type or port._options.configuration.lower()
+ self.graphics_type = graphics_type or port.graphics_type()
+
+ def items(self):
+ return self.__dict__.items()
+
+ def keys(self):
+ return self.__dict__.keys()
+
+ def __str__(self):
+ return ("<%(os)s, %(version)s, %(build_type)s, %(graphics_type)s>" %
+ self.__dict__)
+
+ def __repr__(self):
+ return "TestConfig(os='%(os)s', version='%(version)s', architecture='%(architecture)s', build_type='%(build_type)s', graphics_type='%(graphics_type)s')" % self.__dict__
+
+ def values(self):
+ """Returns the configuration values of this instance as a tuple."""
+ return self.__dict__.values()
+
+ def all_test_configurations(self):
+ """Returns a sequence of the TestConfigurations the port supports."""
+ # By default, we assume we want to test every graphics type in
+ # every configuration on every system.
+ test_configurations = []
+ for system in self.all_systems():
+ for build_type in self.all_build_types():
+ for graphics_type in self.all_graphics_types():
+ test_configurations.append(TestConfiguration(
+ os=system[0],
+ version=system[1],
+ architecture=system[2],
+ build_type=build_type,
+ graphics_type=graphics_type))
+ return test_configurations
+
+ def all_systems(self):
+ return (('mac', 'leopard', 'x86'),
+ ('mac', 'snowleopard', 'x86'),
+ ('win', 'xp', 'x86'),
+ ('win', 'vista', 'x86'),
+ ('win', 'win7', 'x86'),
+ ('linux', 'hardy', 'x86'))
+
+ def all_build_types(self):
+ return ('debug', 'release')
+
+ def all_graphics_types(self):
+ return ('cpu', 'gpu')
diff --git a/Tools/Scripts/webkitpy/layout_tests/port/base_unittest.py b/Tools/Scripts/webkitpy/layout_tests/port/base_unittest.py
index 72f2d05..ef90484 100644
--- a/Tools/Scripts/webkitpy/layout_tests/port/base_unittest.py
+++ b/Tools/Scripts/webkitpy/layout_tests/port/base_unittest.py
@@ -224,19 +224,6 @@ class PortTest(unittest.TestCase):
port = base.Port()
self.assertEqual(port.get_option('foo', 'bar'), 'bar')
- def test_set_option_default__unset(self):
- port = base.Port()
- port.set_option_default('foo', 'bar')
- self.assertEqual(port.get_option('foo'), 'bar')
-
- def test_set_option_default__set(self):
- options, args = optparse.OptionParser().parse_args([])
- options.foo = 'bar'
- port = base.Port(options=options)
- # This call should have no effect.
- port.set_option_default('foo', 'new_bar')
- self.assertEqual(port.get_option('foo'), 'bar')
-
def test_name__unset(self):
port = base.Port()
self.assertEqual(port.name(), None)
@@ -263,7 +250,6 @@ class VirtualTest(unittest.TestCase):
self.assertVirtual(port.test_platform_name)
self.assertVirtual(port.results_directory)
self.assertVirtual(port.test_expectations)
- self.assertVirtual(port.test_base_platform_names)
self.assertVirtual(port.test_platform_name)
self.assertVirtual(port.test_platforms)
self.assertVirtual(port.test_platform_name_to_name, None)
diff --git a/Tools/Scripts/webkitpy/layout_tests/port/chromium.py b/Tools/Scripts/webkitpy/layout_tests/port/chromium.py
index ad1bea6..7d56fa2 100644
--- a/Tools/Scripts/webkitpy/layout_tests/port/chromium.py
+++ b/Tools/Scripts/webkitpy/layout_tests/port/chromium.py
@@ -41,16 +41,9 @@ import webbrowser
from webkitpy.common.system import executive
from webkitpy.common.system.path import cygpath
from webkitpy.layout_tests.layout_package import test_expectations
-from webkitpy.layout_tests.layout_package import test_output
-
-import base
-import http_server
-
-# Chromium DRT on OSX uses WebKitDriver.
-if sys.platform == 'darwin':
- import webkit
-
-import websocket_server
+from webkitpy.layout_tests.port import base
+from webkitpy.layout_tests.port import http_server
+from webkitpy.layout_tests.port import websocket_server
_log = logging.getLogger("webkitpy.layout_tests.port.chromium")
@@ -176,8 +169,6 @@ class ChromiumPort(base.Port):
return result
def driver_name(self):
- if self._options.use_test_shell:
- return "test_shell"
return "DumpRenderTree"
def path_from_chromium_base(self, *comps):
@@ -189,7 +180,7 @@ class ChromiumPort(base.Port):
if offset == -1:
self._chromium_base_dir = self._filesystem.join(
abspath[0:abspath.find('Tools')],
- 'WebKit', 'chromium')
+ 'Source', 'WebKit', 'chromium')
else:
self._chromium_base_dir = abspath[0:offset]
return self._filesystem.join(self._chromium_base_dir, *comps)
@@ -217,8 +208,6 @@ class ChromiumPort(base.Port):
def create_driver(self, worker_number):
"""Starts a new Driver and returns a handle to it."""
- if not self.get_option('use_test_shell') and sys.platform == 'darwin':
- return webkit.WebKitDriver(self, worker_number)
return ChromiumDriver(self, worker_number)
def start_helper(self):
@@ -241,9 +230,6 @@ class ChromiumPort(base.Port):
# http://bugs.python.org/issue1731717
self._helper.wait()
- def test_base_platform_names(self):
- return ('linux', 'mac', 'win')
-
def test_expectations(self):
"""Returns the test expectations for this port.
@@ -273,15 +259,14 @@ class ChromiumPort(base.Port):
all_test_files.update(extra_test_files)
expectations = test_expectations.TestExpectations(
- self, all_test_files, expectations_str, test_platform_name,
- is_debug_mode, is_lint_mode=False, overrides=overrides_str)
+ self, all_test_files, expectations_str, self.test_configuration(),
+ is_lint_mode=False, overrides=overrides_str)
tests_dir = self.layout_tests_dir()
return [self.relative_test_filename(test)
for test in expectations.get_tests_with_result_type(test_expectations.SKIP)]
def test_platform_names(self):
- return self.test_base_platform_names() + ('win-xp',
- 'win-vista', 'win-7')
+ return ('mac', 'win', 'linux', 'win-xp', 'win-vista', 'win-7')
def test_platform_name_to_name(self, test_platform_name):
if test_platform_name in self.test_platform_names():
@@ -340,13 +325,11 @@ class ChromiumPort(base.Port):
def _path_to_image_diff(self):
binary_name = 'ImageDiff'
- if self.get_option('use_test_shell'):
- binary_name = 'image_diff'
return self._build_path(self.get_option('configuration'), binary_name)
class ChromiumDriver(base.Driver):
- """Abstract interface for test_shell."""
+ """Abstract interface for DRT."""
def __init__(self, port, worker_number):
self._port = port
@@ -365,10 +348,7 @@ class ChromiumDriver(base.Driver):
cmd.append("--pixel-tests=" +
self._port._convert_path(self._image_path))
- if self._port.get_option('use_test_shell'):
- cmd.append('--layout-tests')
- else:
- cmd.append('--test-shell')
+ cmd.append('--test-shell')
if self._port.get_option('startup_dialog'):
cmd.append('--testshell-startup-dialog')
@@ -385,14 +365,12 @@ class ChromiumDriver(base.Driver):
if self._port.get_option('stress_deopt'):
cmd.append('--stress-deopt')
- # test_shell does not support accelerated compositing.
- if not self._port.get_option("use_test_shell"):
- if self._port.get_option('accelerated_compositing'):
- cmd.append('--enable-accelerated-compositing')
- if self._port.get_option('accelerated_2d_canvas'):
- cmd.append('--enable-accelerated-2d-canvas')
- if self._port.get_option('enable_hardware_gpu'):
- cmd.append('--enable-hardware-gpu')
+ if self._port.get_option('accelerated_compositing'):
+ cmd.append('--enable-accelerated-compositing')
+ if self._port.get_option('accelerated_2d_canvas'):
+ cmd.append('--enable-accelerated-2d-canvas')
+ if self._port.get_option('enable_hardware_gpu'):
+ cmd.append('--enable-hardware-gpu')
return cmd
def start(self):
@@ -420,17 +398,17 @@ class ChromiumDriver(base.Driver):
try:
if input:
if isinstance(input, unicode):
- # TestShell expects utf-8
+ # DRT expects utf-8
input = input.encode("utf-8")
self._proc.stdin.write(input)
# DumpRenderTree text output is always UTF-8. However some tests
# (e.g. webarchive) may spit out binary data instead of text so we
- # don't bother to decode the output (for either DRT or test_shell).
+ # don't bother to decode the output.
line = self._proc.stdout.readline()
# We could assert() here that line correctly decodes as UTF-8.
return (line, False)
except IOError, e:
- _log.error("IOError communicating w/ test_shell: " + str(e))
+ _log.error("IOError communicating w/ DRT: " + str(e))
return (None, True)
def _test_shell_command(self, uri, timeoutms, checksum):
@@ -465,7 +443,7 @@ class ChromiumDriver(base.Driver):
raise e
return self._output_image()
- def run_test(self, test_input):
+ def run_test(self, driver_input):
output = []
error = []
crash = False
@@ -475,9 +453,9 @@ class ChromiumDriver(base.Driver):
start_time = time.time()
- uri = self._port.filename_to_uri(test_input.filename)
- cmd = self._test_shell_command(uri, test_input.timeout,
- test_input.image_hash)
+ uri = self._port.filename_to_uri(driver_input.filename)
+ cmd = self._test_shell_command(uri, driver_input.timeout,
+ driver_input.image_hash)
(line, crash) = self._write_command_and_read_line(input=cmd)
while not crash and line.rstrip() != "#EOF":
@@ -485,7 +463,7 @@ class ChromiumDriver(base.Driver):
if line == '' and self.poll() is not None:
# This is hex code 0xc000001d, which is used for abrupt
# termination. This happens if we hit ctrl+c from the prompt
- # and we happen to be waiting on test_shell.
+ # and we happen to be waiting on DRT.
# sdoyon: Not sure for which OS and in what circumstances the
# above code is valid. What works for me under Linux to detect
# ctrl+c is for the subprocess returncode to be negative
@@ -519,7 +497,7 @@ class ChromiumDriver(base.Driver):
(line, crash) = self._write_command_and_read_line(input=None)
run_time = time.time() - start_time
- return test_output.TestOutput(
+ return base.DriverOutput(
''.join(output), self._output_image_with_retry(), actual_checksum,
crash, run_time, timeout, ''.join(error))
@@ -532,8 +510,8 @@ class ChromiumDriver(base.Driver):
if sys.platform not in ('win32', 'cygwin'):
# Closing stdin/stdout/stderr hangs sometimes on OS X,
# (see __init__(), above), and anyway we don't want to hang
- # the harness if test_shell is buggy, so we wait a couple
- # seconds to give test_shell a chance to clean up, but then
+ # the harness if DRT is buggy, so we wait a couple
+ # seconds to give DRT a chance to clean up, but then
# force-kill the process if necessary.
KILL_TIMEOUT = 3.0
timeout = time.time() + KILL_TIMEOUT
diff --git a/Tools/Scripts/webkitpy/layout_tests/port/chromium_gpu.py b/Tools/Scripts/webkitpy/layout_tests/port/chromium_gpu.py
index b88d8aa..e8c75c4 100644
--- a/Tools/Scripts/webkitpy/layout_tests/port/chromium_gpu.py
+++ b/Tools/Scripts/webkitpy/layout_tests/port/chromium_gpu.py
@@ -30,64 +30,64 @@ import chromium_linux
import chromium_mac
import chromium_win
+from webkitpy.layout_tests.port import test_files
-def get(**kwargs):
+
+def get(platform=None, port_name='chromium-gpu', **kwargs):
"""Some tests have slightly different results when run while using
hardware acceleration. In those cases, we prepend an additional directory
to the baseline paths."""
- port_name = kwargs.get('port_name', None)
+ platform = platform or sys.platform
if port_name == 'chromium-gpu':
- if sys.platform in ('cygwin', 'win32'):
+ if platform in ('cygwin', 'win32'):
port_name = 'chromium-gpu-win'
- elif sys.platform == 'linux2':
+ elif platform == 'linux2':
port_name = 'chromium-gpu-linux'
- elif sys.platform == 'darwin':
+ elif platform == 'darwin':
port_name = 'chromium-gpu-mac'
else:
- raise NotImplementedError('unsupported platform: %s' %
- sys.platform)
+ raise NotImplementedError('unsupported platform: %s' % platform)
if port_name == 'chromium-gpu-linux':
- return ChromiumGpuLinuxPort(**kwargs)
-
- if port_name.startswith('chromium-gpu-mac'):
- return ChromiumGpuMacPort(**kwargs)
-
- if port_name.startswith('chromium-gpu-win'):
- return ChromiumGpuWinPort(**kwargs)
-
+ return ChromiumGpuLinuxPort(port_name=port_name, **kwargs)
+ if port_name == 'chromium-gpu-mac':
+ return ChromiumGpuMacPort(port_name=port_name, **kwargs)
+ if port_name == 'chromium-gpu-win':
+ return ChromiumGpuWinPort(port_name=port_name, **kwargs)
raise NotImplementedError('unsupported port: %s' % port_name)
-def _set_gpu_options(options):
- if options:
- if options.accelerated_compositing is None:
- options.accelerated_compositing = True
- if options.accelerated_2d_canvas is None:
- options.accelerated_2d_canvas = True
+# FIXME: These should really be a mixin class.
- # FIXME: Remove this after http://codereview.chromium.org/5133001/ is enabled
- # on the bots.
- if options.builder_name is not None and not ' - GPU' in options.builder_name:
- options.builder_name = options.builder_name + ' - GPU'
+def _set_gpu_options(port):
+ if port.get_option('accelerated_compositing') is None:
+ port._options.accelerated_compositing = True
+ if port.get_option('accelerated_2d_canvas') is None:
+ port._options.accelerated_2d_canvas = True
+ # FIXME: Remove this after http://codereview.chromium.org/5133001/ is enabled
+ # on the bots.
+ if port.get_option('builder_name') is not None and not ' - GPU' in port._options.builder_name:
+ port._options.builder_name += ' - GPU'
-def _gpu_overrides(port):
- try:
- overrides_path = port.path_from_chromium_base('webkit', 'tools',
- 'layout_tests', 'test_expectations_gpu.txt')
- except AssertionError:
- return None
- if not port._filesystem.exists(overrides_path):
- return None
- return port._filesystem.read_text_file(overrides_path)
+
+def _tests(port, paths):
+ if not paths:
+ paths = ['compositing', 'platform/chromium/compositing']
+ if not port.name().startswith('chromium-gpu-mac'):
+ # Canvas is not yet accelerated on the Mac, so there's no point
+ # in running the tests there.
+ paths += ['fast/canvas', 'canvas/philip']
+ # invalidate_rect.html tests a bug in the compositor.
+ # See https://bugs.webkit.org/show_bug.cgi?id=53117
+ paths += ['plugins/invalidate_rect.html']
+ return test_files.find(port, paths)
class ChromiumGpuLinuxPort(chromium_linux.ChromiumLinuxPort):
- def __init__(self, **kwargs):
- kwargs.setdefault('port_name', 'chromium-gpu-linux')
- _set_gpu_options(kwargs.get('options'))
- chromium_linux.ChromiumLinuxPort.__init__(self, **kwargs)
+ def __init__(self, port_name='chromium-gpu-linux', **kwargs):
+ chromium_linux.ChromiumLinuxPort.__init__(self, port_name=port_name, **kwargs)
+ _set_gpu_options(self)
def baseline_search_path(self):
# Mimic the Linux -> Win expectations fallback in the ordinary Chromium port.
@@ -97,19 +97,18 @@ class ChromiumGpuLinuxPort(chromium_linux.ChromiumLinuxPort):
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')
+ def graphics_type(self):
+ return 'gpu'
+
+ def tests(self, paths):
+ return _tests(self, paths)
- def test_expectations_overrides(self):
- return _gpu_overrides(self)
class ChromiumGpuMacPort(chromium_mac.ChromiumMacPort):
- def __init__(self, **kwargs):
- kwargs.setdefault('port_name', 'chromium-gpu-mac')
- _set_gpu_options(kwargs.get('options'))
- chromium_mac.ChromiumMacPort.__init__(self, **kwargs)
+ def __init__(self, port_name='chromium-gpu-mac', **kwargs):
+ chromium_mac.ChromiumMacPort.__init__(self, port_name=port_name, **kwargs)
+ _set_gpu_options(self)
def baseline_search_path(self):
return (map(self._webkit_baseline_path, ['chromium-gpu-mac', 'chromium-gpu']) +
@@ -118,19 +117,18 @@ class ChromiumGpuMacPort(chromium_mac.ChromiumMacPort):
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')
+ def graphics_type(self):
+ return 'gpu'
+
+ def tests(self, paths):
+ return _tests(self, paths)
- def test_expectations_overrides(self):
- return _gpu_overrides(self)
class ChromiumGpuWinPort(chromium_win.ChromiumWinPort):
- def __init__(self, **kwargs):
- kwargs.setdefault('port_name', 'chromium-gpu-win' + self.version())
- _set_gpu_options(kwargs.get('options'))
- chromium_win.ChromiumWinPort.__init__(self, **kwargs)
+ def __init__(self, port_name='chromium-gpu-win', **kwargs):
+ chromium_win.ChromiumWinPort.__init__(self, port_name=port_name, **kwargs)
+ _set_gpu_options(self)
def baseline_search_path(self):
return (map(self._webkit_baseline_path, ['chromium-gpu-win', 'chromium-gpu']) +
@@ -139,9 +137,8 @@ class ChromiumGpuWinPort(chromium_win.ChromiumWinPort):
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')
+ def graphics_type(self):
+ return 'gpu'
- def test_expectations_overrides(self):
- return _gpu_overrides(self)
+ def tests(self, paths):
+ return _tests(self, paths)
diff --git a/Tools/Scripts/webkitpy/layout_tests/port/chromium_gpu_unittest.py b/Tools/Scripts/webkitpy/layout_tests/port/chromium_gpu_unittest.py
index 0bfb127..96962ec 100644
--- a/Tools/Scripts/webkitpy/layout_tests/port/chromium_gpu_unittest.py
+++ b/Tools/Scripts/webkitpy/layout_tests/port/chromium_gpu_unittest.py
@@ -40,20 +40,34 @@ class ChromiumGpuTest(unittest.TestCase):
def test_get_chromium_gpu_win(self):
self.assertOverridesWorked('chromium-gpu-win')
- def assertOverridesWorked(self, port_name):
+ def test_get_chromium_gpu__on_linux(self):
+ self.assertOverridesWorked('chromium-gpu-linux', 'chromium-gpu', 'linux2')
+
+ def test_get_chromium_gpu__on_mac(self):
+ self.assertOverridesWorked('chromium-gpu-mac', 'chromium-gpu', 'darwin')
+
+ def test_get_chromium_gpu__on_win(self):
+ self.assertOverridesWorked('chromium-gpu-win', 'chromium-gpu', 'win32')
+ self.assertOverridesWorked('chromium-gpu-win', 'chromium-gpu', 'cygwin')
+
+ def assertOverridesWorked(self, port_name, input_name=None, platform=None):
# test that we got the right port
mock_options = mocktool.MockOptions(accelerated_compositing=None,
accelerated_2d_canvas=None,
builder_name='foo',
child_processes=None)
- port = chromium_gpu.get(port_name=port_name, options=mock_options)
+ if input_name and platform:
+ port = chromium_gpu.get(platform=platform, port_name=input_name,
+ options=mock_options)
+ else:
+ 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.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.
- self.assertTrue(port.name().startswith(port_name))
+ # We don't support platform-specific versions of the GPU port yet.
+ self.assertEqual(port.name(), port_name)
# test that it has the right directories in front of the search path.
paths = port.baseline_search_path()
@@ -64,9 +78,24 @@ class ChromiumGpuTest(unittest.TestCase):
else:
self.assertEqual(port._webkit_baseline_path('chromium-gpu'), paths[1])
- # Test that we have the right expectations file.
- self.assertTrue('chromium-gpu' in
- port.path_to_test_expectations_file())
+
+ # Test that we're limiting to the correct directories.
+ # These two tests are picked mostly at random, but we make sure they
+ # exist separately from being filtered out by the port.
+ files = port.tests(None)
+
+ path = port.abspath_for_test('compositing/checkerboard.html')
+ self.assertTrue(port._filesystem.exists(path))
+ self.assertTrue(path in files)
+
+ path = port.abspath_for_test('fast/html/keygen.html')
+ self.assertTrue(port._filesystem.exists(path))
+ self.assertFalse(path in files)
+ if port_name.startswith('chromium-gpu-mac'):
+ path = port.abspath_for_test('fast/canvas/set-colors.html')
+ self.assertTrue(port._filesystem.exists(path))
+ self.assertFalse(path in files)
+
if __name__ == '__main__':
unittest.main()
diff --git a/Tools/Scripts/webkitpy/layout_tests/port/chromium_linux.py b/Tools/Scripts/webkitpy/layout_tests/port/chromium_linux.py
index c1c85f8..c3c5a21 100644
--- a/Tools/Scripts/webkitpy/layout_tests/port/chromium_linux.py
+++ b/Tools/Scripts/webkitpy/layout_tests/port/chromium_linux.py
@@ -85,7 +85,7 @@ class ChromiumLinuxPort(chromium.ChromiumPort):
base = self.path_from_chromium_base()
if self._filesystem.exists(self._filesystem.join(base, 'sconsbuild')):
return self._filesystem.join(base, 'sconsbuild', *comps)
- if self._filesystem.exists(self._filesystem.join(base, 'out', *comps)) or self.get_option('use_test_shell'):
+ if self._filesystem.exists(self._filesystem.join(base, 'out', *comps)):
return self._filesystem.join(base, 'out', *comps)
base = self.path_from_webkit_base()
if self._filesystem.exists(self._filesystem.join(base, 'sconsbuild')):
@@ -153,8 +153,6 @@ class ChromiumLinuxPort(chromium.ChromiumPort):
if not configuration:
configuration = self.get_option('configuration')
binary_name = 'DumpRenderTree'
- if self.get_option('use_test_shell'):
- binary_name = 'test_shell'
return self._build_path(configuration, binary_name)
def _path_to_helper(self):
diff --git a/Tools/Scripts/webkitpy/layout_tests/port/chromium_mac.py b/Tools/Scripts/webkitpy/layout_tests/port/chromium_mac.py
index 5360ab3..17862a2 100644
--- a/Tools/Scripts/webkitpy/layout_tests/port/chromium_mac.py
+++ b/Tools/Scripts/webkitpy/layout_tests/port/chromium_mac.py
@@ -69,18 +69,18 @@ class ChromiumMacPort(chromium.ChromiumPort):
return result
def default_child_processes(self):
- # FIXME: we need to run single-threaded for now. See
- # https://bugs.webkit.org/show_bug.cgi?id=38553. Unfortunately this
- # routine is called right before the logger is configured, so if we
- # try to _log.warning(), it gets thrown away.
- import sys
- sys.stderr.write("Defaulting to one child - see https://bugs.webkit.org/show_bug.cgi?id=38553\n")
- return 1
+ if self.get_option('worker_model') == 'old-threads':
+ # FIXME: we need to run single-threaded for now. See
+ # https://bugs.webkit.org/show_bug.cgi?id=38553. Unfortunately this
+ # routine is called right before the logger is configured, so if we
+ # try to _log.warning(), it gets thrown away.
+ import sys
+ sys.stderr.write("Defaulting to one child - see https://bugs.webkit.org/show_bug.cgi?id=38553\n")
+ return 1
+
+ return chromium.ChromiumPort.default_child_processes(self)
def driver_name(self):
- """name for this port's equivalent of DumpRenderTree."""
- if self.get_option('use_test_shell'):
- return "TestShell"
return "DumpRenderTree"
def test_platform_name(self):
@@ -110,7 +110,7 @@ class ChromiumMacPort(chromium.ChromiumPort):
*comps)
path = self.path_from_chromium_base('xcodebuild', *comps)
- if self._filesystem.exists(path) or self.get_option('use_test_shell'):
+ if self._filesystem.exists(path):
return path
return self.path_from_webkit_base(
'Source', 'WebKit', 'chromium', 'xcodebuild', *comps)
@@ -154,8 +154,6 @@ class ChromiumMacPort(chromium.ChromiumPort):
def _path_to_helper(self):
binary_name = 'LayoutTestHelper'
- if self.get_option('use_test_shell'):
- binary_name = 'layout_test_helper'
return self._build_path(self.get_option('configuration'), binary_name)
def _path_to_wdiff(self):
diff --git a/Tools/Scripts/webkitpy/layout_tests/port/chromium_unittest.py b/Tools/Scripts/webkitpy/layout_tests/port/chromium_unittest.py
index 6c8987b..b89c8cc 100644
--- a/Tools/Scripts/webkitpy/layout_tests/port/chromium_unittest.py
+++ b/Tools/Scripts/webkitpy/layout_tests/port/chromium_unittest.py
@@ -116,13 +116,6 @@ class ChromiumPortTest(unittest.TestCase):
port = ChromiumPortTest.TestMacPort(options=mock_options)
self.assertTrue(port._path_to_image_diff().endswith(
'/xcodebuild/default/ImageDiff'))
- mock_options = mocktool.MockOptions(use_test_shell=True)
- port = ChromiumPortTest.TestLinuxPort(options=mock_options)
- self.assertTrue(port._path_to_image_diff().endswith(
- '/out/default/image_diff'), msg=port._path_to_image_diff())
- port = ChromiumPortTest.TestMacPort(options=mock_options)
- self.assertTrue(port._path_to_image_diff().endswith(
- '/xcodebuild/default/image_diff'))
# FIXME: Figure out how this is going to work on Windows.
#port = chromium_win.ChromiumWinPort('test-port', options=MockOptions())
diff --git a/Tools/Scripts/webkitpy/layout_tests/port/chromium_win.py b/Tools/Scripts/webkitpy/layout_tests/port/chromium_win.py
index 14f2777..f4cbf80 100644
--- a/Tools/Scripts/webkitpy/layout_tests/port/chromium_win.py
+++ b/Tools/Scripts/webkitpy/layout_tests/port/chromium_win.py
@@ -113,9 +113,9 @@ class ChromiumWinPort(chromium.ChromiumPort):
if self._filesystem.exists(p):
return p
p = self.path_from_chromium_base('chrome', *comps)
- if self._filesystem.exists(p) or self.get_option('use_test_shell'):
+ if self._filesystem.exists(p):
return p
- return self._filesystem.join(self.path_from_webkit_base(), 'WebKit', 'chromium', *comps)
+ return self._filesystem.join(self.path_from_webkit_base(), 'Source', 'WebKit', 'chromium', *comps)
def _lighttpd_path(self, *comps):
return self.path_from_chromium_base('third_party', 'lighttpd', 'win',
@@ -141,20 +141,14 @@ class ChromiumWinPort(chromium.ChromiumPort):
if not configuration:
configuration = self.get_option('configuration')
binary_name = 'DumpRenderTree.exe'
- if self.get_option('use_test_shell'):
- binary_name = 'test_shell.exe'
return self._build_path(configuration, binary_name)
def _path_to_helper(self):
binary_name = 'LayoutTestHelper.exe'
- if self.get_option('use_test_shell'):
- binary_name = 'layout_test_helper.exe'
return self._build_path(self.get_option('configuration'), binary_name)
def _path_to_image_diff(self):
binary_name = 'ImageDiff.exe'
- if self.get_option('use_test_shell'):
- binary_name = 'image_diff.exe'
return self._build_path(self.get_option('configuration'), binary_name)
def _path_to_wdiff(self):
diff --git a/Tools/Scripts/webkitpy/layout_tests/port/dryrun.py b/Tools/Scripts/webkitpy/layout_tests/port/dryrun.py
index 4ed34e6..6b3bd51 100644
--- a/Tools/Scripts/webkitpy/layout_tests/port/dryrun.py
+++ b/Tools/Scripts/webkitpy/layout_tests/port/dryrun.py
@@ -50,8 +50,6 @@ import os
import sys
import time
-from webkitpy.layout_tests.layout_package import test_output
-
import base
import factory
@@ -71,6 +69,12 @@ class DryRunPort(object):
def __getattr__(self, name):
return getattr(self.__delegate, name)
+ def acquire_http_lock(self):
+ pass
+
+ def release_http_lock(self):
+ pass
+
def check_build(self, needs_http):
return True
@@ -112,18 +116,18 @@ class DryrunDriver(base.Driver):
def poll(self):
return None
- def run_test(self, test_input):
+ def run_test(self, driver_input):
start_time = time.time()
- text_output = self._port.expected_text(test_input.filename)
+ text_output = self._port.expected_text(driver_input.filename)
- if test_input.image_hash is not None:
- image = self._port.expected_image(test_input.filename)
- hash = self._port.expected_checksum(test_input.filename)
+ if driver_input.image_hash is not None:
+ image = self._port.expected_image(driver_input.filename)
+ hash = self._port.expected_checksum(driver_input.filename)
else:
image = None
hash = None
- return test_output.TestOutput(text_output, image, hash, False,
- time.time() - start_time, False, None)
+ return base.DriverOutput(text_output, image, hash, False,
+ time.time() - start_time, False, '')
def start(self):
pass
diff --git a/Tools/Scripts/webkitpy/layout_tests/port/factory.py b/Tools/Scripts/webkitpy/layout_tests/port/factory.py
index 6935744..7ae6eb6 100644
--- a/Tools/Scripts/webkitpy/layout_tests/port/factory.py
+++ b/Tools/Scripts/webkitpy/layout_tests/port/factory.py
@@ -70,12 +70,15 @@ def _get_kwargs(**kwargs):
raise NotImplementedError('unknown port; sys.platform = "%s"' %
sys.platform)
- if port_to_use == 'test':
+ if port_to_use.startswith('test'):
import test
maker = test.TestPort
elif port_to_use.startswith('dryrun'):
import dryrun
maker = dryrun.DryRunPort
+ elif port_to_use.startswith('mock-'):
+ import mock_drt
+ maker = mock_drt.MockDRTPort
elif port_to_use.startswith('mac'):
import mac
maker = mac.MacPort
diff --git a/Tools/Scripts/webkitpy/layout_tests/port/http_server_base.py b/Tools/Scripts/webkitpy/layout_tests/port/http_server_base.py
index 52a0403..2a43e81 100644
--- a/Tools/Scripts/webkitpy/layout_tests/port/http_server_base.py
+++ b/Tools/Scripts/webkitpy/layout_tests/port/http_server_base.py
@@ -67,7 +67,7 @@ class HttpServerBase(object):
url = 'http%s://127.0.0.1:%d/' % (http_suffix, mapping['port'])
try:
- response = urllib.urlopen(url)
+ response = urllib.urlopen(url, proxies={})
_log.debug("Server running at %s" % url)
except IOError, e:
_log.debug("Server NOT running at %s: %s" % (url, e))
diff --git a/Tools/Scripts/webkitpy/layout_tests/port/mac.py b/Tools/Scripts/webkitpy/layout_tests/port/mac.py
index 0622196..1398ed3 100644
--- a/Tools/Scripts/webkitpy/layout_tests/port/mac.py
+++ b/Tools/Scripts/webkitpy/layout_tests/port/mac.py
@@ -33,9 +33,7 @@ import os
import platform
import signal
-import webkitpy.common.system.ospath as ospath
-import webkitpy.layout_tests.port.server_process as server_process
-from webkitpy.layout_tests.port.webkit import WebKitPort, WebKitDriver
+from webkitpy.layout_tests.port.webkit import WebKitPort
_log = logging.getLogger("webkitpy.layout_tests.port.mac")
@@ -52,7 +50,7 @@ class MacPort(WebKitPort):
# four threads in parallel.
# See https://bugs.webkit.org/show_bug.cgi?id=36622
child_processes = WebKitPort.default_child_processes(self)
- if child_processes > 4:
+ if self.get_option('worker_model') == 'old-threads' and child_processes > 4:
return 4
return child_processes
diff --git a/Tools/Scripts/webkitpy/layout_tests/port/mac_unittest.py b/Tools/Scripts/webkitpy/layout_tests/port/mac_unittest.py
index d383a4c..ef04679 100644
--- a/Tools/Scripts/webkitpy/layout_tests/port/mac_unittest.py
+++ b/Tools/Scripts/webkitpy/layout_tests/port/mac_unittest.py
@@ -35,23 +35,31 @@ import port_testcase
class MacTest(port_testcase.PortTestCase):
- def make_port(self, options=port_testcase.mock_options):
+ def make_port(self, port_name=None, options=port_testcase.mock_options):
if sys.platform != 'darwin':
return None
- port_obj = mac.MacPort(options=options)
+ port_obj = mac.MacPort(port_name=port_name, options=options)
port_obj._options.results_directory = port_obj.results_directory()
port_obj._options.configuration = 'Release'
return port_obj
- def test_skipped_file_paths(self):
- port = self.make_port()
+ def assert_skipped_files_for_version(self, port_name, expected_paths):
+ port = self.make_port(port_name)
if not port:
return
skipped_paths = port._skipped_file_paths()
# FIXME: _skipped_file_paths should return WebKit-relative paths.
# So to make it unit testable, we strip the WebKit directory from the path.
relative_paths = [path[len(port.path_from_webkit_base()):] for path in skipped_paths]
- self.assertEqual(relative_paths, ['LayoutTests/platform/mac-leopard/Skipped', 'LayoutTests/platform/mac/Skipped'])
+ self.assertEqual(relative_paths, expected_paths)
+
+ def test_skipped_file_paths(self):
+ self.assert_skipped_files_for_version('mac',
+ ['/LayoutTests/platform/mac/Skipped'])
+ self.assert_skipped_files_for_version('mac-snowleopard',
+ ['/LayoutTests/platform/mac-snowleopard/Skipped', '/LayoutTests/platform/mac/Skipped'])
+ self.assert_skipped_files_for_version('mac-leopard',
+ ['/LayoutTests/platform/mac-leopard/Skipped', '/LayoutTests/platform/mac/Skipped'])
example_skipped_file = u"""
# <rdar://problem/5647952> fast/events/mouseout-on-window.html needs mac DRT to issue mouse out events
@@ -69,12 +77,11 @@ svg/batik/text/smallFonts.svg
"svg/batik/text/smallFonts.svg",
]
- def test_skipped_file_paths(self):
+ def test_tests_from_skipped_file_contents(self):
port = self.make_port()
if not port:
return
- skipped_file = StringIO.StringIO(self.example_skipped_file)
- self.assertEqual(port._tests_from_skipped_file(skipped_file), self.example_skipped_tests)
+ self.assertEqual(port._tests_from_skipped_file_contents(self.example_skipped_file), self.example_skipped_tests)
if __name__ == '__main__':
diff --git a/Tools/Scripts/webkitpy/layout_tests/port/mock_drt.py b/Tools/Scripts/webkitpy/layout_tests/port/mock_drt.py
new file mode 100644
index 0000000..1147846
--- /dev/null
+++ b/Tools/Scripts/webkitpy/layout_tests/port/mock_drt.py
@@ -0,0 +1,280 @@
+#!/usr/bin/env python
+# Copyright (C) 2011 Google Inc. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+# * Neither the Google name nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+"""
+This is an implementation of the Port interface that overrides other
+ports and changes the Driver binary to "MockDRT".
+"""
+
+import logging
+import optparse
+import os
+import sys
+
+from webkitpy.common.system import filesystem
+
+from webkitpy.layout_tests.port import base
+from webkitpy.layout_tests.port import factory
+
+_log = logging.getLogger(__name__)
+
+
+class MockDRTPort(object):
+ """MockPort implementation of the Port interface."""
+
+ def __init__(self, **kwargs):
+ prefix = 'mock-'
+ if 'port_name' in kwargs:
+ kwargs['port_name'] = kwargs['port_name'][len(prefix):]
+ self.__delegate = factory.get(**kwargs)
+ self.__real_name = prefix + self.__delegate.name()
+
+ def real_name(self):
+ return self.__real_name
+
+ def __getattr__(self, name):
+ return getattr(self.__delegate, name)
+
+ def acquire_http_lock(self):
+ pass
+
+ def release_http_lock(self):
+ pass
+
+ def check_build(self, needs_http):
+ return True
+
+ def check_sys_deps(self, needs_http):
+ return True
+
+ def driver_cmd_line(self):
+ driver = self.create_driver(0)
+ return driver.cmd_line()
+
+ def _path_to_driver(self):
+ return os.path.abspath(__file__)
+
+ def create_driver(self, worker_number):
+ # We need to create a driver object as the delegate would, but
+ # overwrite the path to the driver binary in its command line. We do
+ # this by actually overwriting its cmd_line() method with a proxy
+ # method that splices in the mock_drt path and command line arguments
+ # in place of the actual path to the driver binary.
+
+ def overriding_cmd_line():
+ cmd = self.__original_driver_cmd_line()
+ index = cmd.index(self.__delegate._path_to_driver())
+ cmd[index:index + 1] = [sys.executable, self._path_to_driver(),
+ '--platform', self.name()]
+ return cmd
+
+ delegated_driver = self.__delegate.create_driver(worker_number)
+ self.__original_driver_cmd_line = delegated_driver.cmd_line
+ delegated_driver.cmd_line = overriding_cmd_line
+ return delegated_driver
+
+ def start_helper(self):
+ pass
+
+ def start_http_server(self):
+ pass
+
+ def start_websocket_server(self):
+ pass
+
+ def stop_helper(self):
+ pass
+
+ def stop_http_server(self):
+ pass
+
+ def stop_websocket_server(self):
+ pass
+
+
+def main(argv, fs, stdin, stdout, stderr):
+ """Run the tests."""
+
+ options, args = parse_options(argv)
+ if options.chromium:
+ drt = MockChromiumDRT(options, args, fs, stdin, stdout, stderr)
+ else:
+ drt = MockDRT(options, args, fs, stdin, stdout, stderr)
+ return drt.run()
+
+
+def parse_options(argv):
+ # FIXME: We have to do custom arg parsing instead of using the optparse
+ # module. First, Chromium and non-Chromium DRTs have a different argument
+ # syntax. Chromium uses --pixel-tests=<path>, and non-Chromium uses
+ # --pixel-tests as a boolean flag. Second, we don't want to have to list
+ # every command line flag DRT accepts, but optparse complains about
+ # unrecognized flags. At some point it might be good to share a common
+ # DRT options class between this file and webkit.py and chromium.py
+ # just to get better type checking.
+ platform_index = argv.index('--platform')
+ platform = argv[platform_index + 1]
+
+ pixel_tests = False
+ pixel_path = None
+ chromium = False
+ if platform.startswith('chromium'):
+ chromium = True
+ for arg in argv:
+ if arg.startswith('--pixel-tests'):
+ pixel_tests = True
+ pixel_path = arg[len('--pixel-tests='):]
+ else:
+ pixel_tests = '--pixel-tests' in argv
+ options = base.DummyOptions(chromium=chromium,
+ platform=platform,
+ pixel_tests=pixel_tests,
+ pixel_path=pixel_path)
+ return (options, [])
+
+
+# FIXME: Should probably change this to use DriverInput after
+# https://bugs.webkit.org/show_bug.cgi?id=53004 lands.
+class _DRTInput(object):
+ def __init__(self, line):
+ vals = line.strip().split("'")
+ if len(vals) == 1:
+ self.uri = vals[0]
+ self.checksum = None
+ else:
+ self.uri = vals[0]
+ self.checksum = vals[1]
+
+
+class MockDRT(object):
+ def __init__(self, options, args, filesystem, stdin, stdout, stderr):
+ self._options = options
+ self._args = args
+ self._filesystem = filesystem
+ self._stdout = stdout
+ self._stdin = stdin
+ self._stderr = stderr
+
+ port_name = None
+ if options.platform:
+ port_name = options.platform
+ self._port = factory.get(port_name, options=options, filesystem=filesystem)
+
+ def run(self):
+ while True:
+ line = self._stdin.readline()
+ if not line:
+ break
+ self.run_one_test(self.parse_input(line))
+ return 0
+
+ def parse_input(self, line):
+ return _DRTInput(line)
+
+ def run_one_test(self, test_input):
+ port = self._port
+ if test_input.uri.startswith('http'):
+ test_name = port.uri_to_test_name(test_input.uri)
+ test_path = self._filesystem.join(port.layout_tests_dir(), test_name)
+ else:
+ test_path = test_input.uri
+
+ actual_text = port.expected_text(test_path)
+ if self._options.pixel_tests and test_input.checksum:
+ actual_checksum = port.expected_checksum(test_path)
+ actual_image = port.expected_image(test_path)
+
+ self._stdout.write('Content-Type: text/plain\n')
+
+ # FIXME: Note that we don't ensure there is a trailing newline!
+ # This mirrors actual (Mac) DRT behavior but is a bug.
+ self._stdout.write(actual_text)
+ self._stdout.write('#EOF\n')
+
+ if self._options.pixel_tests and test_input.checksum:
+ self._stdout.write('\n')
+ self._stdout.write('ActualHash: %s\n' % actual_checksum)
+ self._stdout.write('ExpectedHash: %s\n' % test_input.checksum)
+ if actual_checksum != test_input.checksum:
+ self._stdout.write('Content-Type: image/png\n')
+ self._stdout.write('Content-Length: %s\n\n' % len(actual_image))
+ self._stdout.write(actual_image)
+ self._stdout.write('#EOF\n')
+ self._stdout.flush()
+ self._stderr.flush()
+
+
+# FIXME: Should probably change this to use DriverInput after
+# https://bugs.webkit.org/show_bug.cgi?id=53004 lands.
+class _ChromiumDRTInput(_DRTInput):
+ def __init__(self, line):
+ vals = line.strip().split()
+ if len(vals) == 3:
+ self.uri, self.timeout, self.checksum = vals
+ else:
+ self.uri = vals[0]
+ self.timeout = vals[1]
+ self.checksum = None
+
+
+class MockChromiumDRT(MockDRT):
+ def parse_input(self, line):
+ return _ChromiumDRTInput(line)
+
+ def run_one_test(self, test_input):
+ port = self._port
+ test_name = self._port.uri_to_test_name(test_input.uri)
+ test_path = self._filesystem.join(port.layout_tests_dir(), test_name)
+
+ actual_text = port.expected_text(test_path)
+ actual_image = ''
+ actual_checksum = ''
+ if self._options.pixel_tests and test_input.checksum:
+ actual_checksum = port.expected_checksum(test_path)
+ if actual_checksum != test_input.checksum:
+ actual_image = port.expected_image(test_path)
+
+ self._stdout.write("#URL:%s\n" % test_input.uri)
+ if self._options.pixel_tests and test_input.checksum:
+ self._stdout.write("#MD5:%s\n" % actual_checksum)
+ self._filesystem.write_binary_file(self._options.pixel_path,
+ actual_image)
+ self._stdout.write(actual_text)
+
+ # FIXME: (See above FIXME as well). Chromium DRT appears to always
+ # ensure the text output has a trailing newline. Mac DRT does not.
+ if not actual_text.endswith('\n'):
+ self._stdout.write('\n')
+ self._stdout.write('#EOF\n')
+ self._stdout.flush()
+
+
+if __name__ == '__main__':
+ fs = filesystem.FileSystem()
+ sys.exit(main(sys.argv[1:], fs, sys.stdin, sys.stdout, sys.stderr))
diff --git a/Tools/Scripts/webkitpy/layout_tests/port/mock_drt_unittest.py b/Tools/Scripts/webkitpy/layout_tests/port/mock_drt_unittest.py
new file mode 100644
index 0000000..1506315
--- /dev/null
+++ b/Tools/Scripts/webkitpy/layout_tests/port/mock_drt_unittest.py
@@ -0,0 +1,261 @@
+#!/usr/bin/env python
+# Copyright (C) 2011 Google Inc. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+# * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+"""Unit tests for MockDRT."""
+
+import unittest
+
+from webkitpy.common import newstringio
+
+from webkitpy.layout_tests.port import mock_drt
+from webkitpy.layout_tests.port import factory
+from webkitpy.layout_tests.port import port_testcase
+from webkitpy.layout_tests.port import test
+
+
+class MockDRTPortTest(port_testcase.PortTestCase):
+ def make_port(self):
+ return mock_drt.MockDRTPort()
+
+ def test_port_name_in_constructor(self):
+ self.assertTrue(mock_drt.MockDRTPort(port_name='mock-test'))
+
+ def test_acquire_http_lock(self):
+ # Only checking that no exception is raised.
+ self.make_port().acquire_http_lock()
+
+ def test_release_http_lock(self):
+ # Only checking that no exception is raised.
+ self.make_port().release_http_lock()
+
+ def test_check_build(self):
+ port = self.make_port()
+ self.assertTrue(port.check_build(True))
+
+ def test_check_sys_deps(self):
+ port = self.make_port()
+ self.assertTrue(port.check_sys_deps(True))
+
+ def test_start_helper(self):
+ # Only checking that no exception is raised.
+ self.make_port().start_helper()
+
+ def test_start_http_server(self):
+ # Only checking that no exception is raised.
+ self.make_port().start_http_server()
+
+ def test_start_websocket_server(self):
+ # Only checking that no exception is raised.
+ self.make_port().start_websocket_server()
+
+ def test_stop_helper(self):
+ # Only checking that no exception is raised.
+ self.make_port().stop_helper()
+
+ def test_stop_http_server(self):
+ # Only checking that no exception is raised.
+ self.make_port().stop_http_server()
+
+ def test_stop_websocket_server(self):
+ # Only checking that no exception is raised.
+ self.make_port().stop_websocket_server()
+
+
+class MockDRTTest(unittest.TestCase):
+ def to_path(self, port, test_name):
+ return port._filesystem.join(port.layout_tests_dir(), test_name)
+
+ def input_line(self, port, test_name, checksum=None):
+ url = port.filename_to_uri(self.to_path(port, test_name))
+ # FIXME: we shouldn't have to work around platform-specific issues
+ # here.
+ if url.startswith('file:////'):
+ url = url[len('file:////') - 1:]
+ if url.startswith('file:///'):
+ url = url[len('file:///') - 1:]
+
+ if checksum:
+ return url + "'" + checksum + '\n'
+ return url + '\n'
+
+ def extra_args(self, pixel_tests):
+ if pixel_tests:
+ return ['--pixel-tests', '-']
+ return ['-']
+
+ def make_drt(self, options, args, filesystem, stdin, stdout, stderr):
+ return mock_drt.MockDRT(options, args, filesystem, stdin, stdout, stderr)
+
+ def make_input_output(self, port, test_name, pixel_tests,
+ expected_checksum, drt_output, drt_input=None):
+ path = self.to_path(port, test_name)
+ if pixel_tests:
+ if not expected_checksum:
+ expected_checksum = port.expected_checksum(path)
+ if not drt_input:
+ drt_input = self.input_line(port, test_name, expected_checksum)
+ text_output = port.expected_text(path)
+
+ if not drt_output:
+ drt_output = self.expected_output(port, test_name, pixel_tests,
+ text_output, expected_checksum)
+ return (drt_input, drt_output)
+
+ def expected_output(self, port, test_name, pixel_tests, text_output, expected_checksum):
+ if pixel_tests and expected_checksum:
+ return ['Content-Type: text/plain\n',
+ text_output,
+ '#EOF\n',
+ '\n',
+ 'ActualHash: %s\n' % expected_checksum,
+ 'ExpectedHash: %s\n' % expected_checksum,
+ '#EOF\n']
+ else:
+ return ['Content-Type: text/plain\n',
+ text_output,
+ '#EOF\n',
+ '#EOF\n']
+
+ def assertTest(self, test_name, pixel_tests, expected_checksum=None,
+ drt_output=None, filesystem=None):
+ platform = 'test'
+ filesystem = filesystem or test.unit_test_filesystem()
+ port = factory.get(platform, filesystem=filesystem)
+ drt_input, drt_output = self.make_input_output(port, test_name,
+ pixel_tests, expected_checksum, drt_output)
+
+ args = ['--platform', 'test'] + self.extra_args(pixel_tests)
+ stdin = newstringio.StringIO(drt_input)
+ stdout = newstringio.StringIO()
+ stderr = newstringio.StringIO()
+ options, args = mock_drt.parse_options(args)
+
+ drt = self.make_drt(options, args, filesystem, stdin, stdout, stderr)
+ res = drt.run()
+
+ self.assertEqual(res, 0)
+
+ # We use the StringIO.buflist here instead of getvalue() because
+ # the StringIO might be a mix of unicode/ascii and 8-bit strings.
+ self.assertEqual(stdout.buflist, drt_output)
+ self.assertEqual(stderr.getvalue(), '')
+
+ def test_main(self):
+ filesystem = test.unit_test_filesystem()
+ stdin = newstringio.StringIO()
+ stdout = newstringio.StringIO()
+ stderr = newstringio.StringIO()
+ res = mock_drt.main(['--platform', 'test'] + self.extra_args(False),
+ filesystem, stdin, stdout, stderr)
+ self.assertEqual(res, 0)
+ self.assertEqual(stdout.getvalue(), '')
+ self.assertEqual(stderr.getvalue(), '')
+ self.assertEqual(filesystem.written_files, {})
+
+ def test_pixeltest_passes(self):
+ # This also tests that we handle HTTP: test URLs properly.
+ self.assertTest('http/tests/passes/text.html', True)
+
+ def test_pixeltest__fails(self):
+ self.assertTest('failures/expected/checksum.html', pixel_tests=True,
+ expected_checksum='wrong-checksum',
+ drt_output=['Content-Type: text/plain\n',
+ 'checksum-txt',
+ '#EOF\n',
+ '\n',
+ 'ActualHash: checksum-checksum\n',
+ 'ExpectedHash: wrong-checksum\n',
+ 'Content-Type: image/png\n',
+ 'Content-Length: 13\n\n',
+ 'checksum\x8a-png',
+ '#EOF\n'])
+
+ def test_textonly(self):
+ self.assertTest('passes/image.html', False)
+
+
+class MockChromiumDRTTest(MockDRTTest):
+ def extra_args(self, pixel_tests):
+ if pixel_tests:
+ return ['--pixel-tests=/tmp/png_result0.png']
+ return []
+
+ def make_drt(self, options, args, filesystem, stdin, stdout, stderr):
+ options.chromium = True
+
+ # We have to set these by hand because --platform test won't trigger
+ # the Chromium code paths.
+ options.pixel_path = '/tmp/png_result0.png'
+ options.pixel_tests = True
+
+ return mock_drt.MockChromiumDRT(options, args, filesystem, stdin, stdout, stderr)
+
+ def input_line(self, port, test_name, checksum=None):
+ url = port.filename_to_uri(self.to_path(port, test_name))
+ if checksum:
+ return url + ' 6000 ' + checksum + '\n'
+ return url + ' 6000\n'
+
+ def expected_output(self, port, test_name, pixel_tests, text_output, expected_checksum):
+ url = port.filename_to_uri(self.to_path(port, test_name))
+ if pixel_tests and expected_checksum:
+ return ['#URL:%s\n' % url,
+ '#MD5:%s\n' % expected_checksum,
+ text_output,
+ '\n',
+ '#EOF\n']
+ else:
+ return ['#URL:%s\n' % url,
+ text_output,
+ '\n',
+ '#EOF\n']
+
+ def test_pixeltest__fails(self):
+ filesystem = test.unit_test_filesystem()
+ self.assertTest('failures/expected/checksum.html', pixel_tests=True,
+ expected_checksum='wrong-checksum',
+ drt_output=['#URL:file:///test.checkout/LayoutTests/failures/expected/checksum.html\n',
+ '#MD5:checksum-checksum\n',
+ 'checksum-txt',
+ '\n',
+ '#EOF\n'],
+ filesystem=filesystem)
+ self.assertEquals(filesystem.written_files,
+ {'/tmp/png_result0.png': 'checksum\x8a-png'})
+
+ def test_chromium_parse_options(self):
+ options, args = mock_drt.parse_options(['--platform', 'chromium-mac',
+ '--pixel-tests=/tmp/png_result0.png'])
+ self.assertTrue(options.chromium)
+ self.assertTrue(options.pixel_tests)
+ self.assertEquals(options.pixel_path, '/tmp/png_result0.png')
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/Tools/Scripts/webkitpy/layout_tests/port/port_testcase.py b/Tools/Scripts/webkitpy/layout_tests/port/port_testcase.py
index 0b03b4c..4146d40 100644
--- a/Tools/Scripts/webkitpy/layout_tests/port/port_testcase.py
+++ b/Tools/Scripts/webkitpy/layout_tests/port/port_testcase.py
@@ -88,3 +88,15 @@ class PortTestCase(unittest.TestCase):
return
port.start_websocket_server()
port.stop_websocket_server()
+
+ def test_test_configuration(self):
+ port = self.make_port()
+ if not port:
+ return
+ self.assertTrue(port.test_configuration())
+
+ def test_all_test_configurations(self):
+ port = self.make_port()
+ if not port:
+ return
+ self.assertTrue(len(port.all_test_configurations()) > 0)
diff --git a/Tools/Scripts/webkitpy/layout_tests/port/server_process.py b/Tools/Scripts/webkitpy/layout_tests/port/server_process.py
index 5a0a40c..7974f94 100644
--- a/Tools/Scripts/webkitpy/layout_tests/port/server_process.py
+++ b/Tools/Scripts/webkitpy/layout_tests/port/server_process.py
@@ -115,7 +115,11 @@ class ServerProcess:
if is not already running."""
if not self._proc:
self._start()
- self._proc.stdin.write(input)
+ try:
+ self._proc.stdin.write(input)
+ except IOError, e:
+ self.stop()
+ self.crashed = True
def read_line(self, timeout):
"""Read a single line from the subprocess, waiting until the deadline.
diff --git a/Tools/Scripts/webkitpy/layout_tests/port/server_process_unittest.py b/Tools/Scripts/webkitpy/layout_tests/port/server_process_unittest.py
new file mode 100644
index 0000000..f3429cb
--- /dev/null
+++ b/Tools/Scripts/webkitpy/layout_tests/port/server_process_unittest.py
@@ -0,0 +1,77 @@
+# Copyright (C) 2011 Google Inc. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+# * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+import unittest
+
+from webkitpy.layout_tests.port import server_process
+
+
+class MockFile(object):
+ def __init__(self, server_process):
+ self._server_process = server_process
+
+ def fileno(self):
+ return 1
+
+ def write(self, line):
+ self._server_process.broken_pipes.append(self)
+ raise IOError
+
+ def close(self):
+ pass
+
+
+class MockProc(object):
+ def __init__(self, server_process):
+ self.stdin = MockFile(server_process)
+ self.stdout = MockFile(server_process)
+ self.stderr = MockFile(server_process)
+ self.pid = 1
+
+ def poll(self):
+ return 1
+
+
+class FakeServerProcess(server_process.ServerProcess):
+ def _start(self):
+ self._proc = MockProc(self)
+ self.stdin = self._proc.stdin
+ self.broken_pipes = []
+
+
+class TestServerProcess(unittest.TestCase):
+ def test_broken_pipe(self):
+ server_process = FakeServerProcess(port_obj=None, name="test", cmd=["test"])
+ server_process.write("should break")
+ self.assertTrue(server_process.crashed)
+ self.assertEquals(server_process._proc, None)
+ self.assertEquals(server_process.broken_pipes, [server_process.stdin])
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/Tools/Scripts/webkitpy/layout_tests/port/test.py b/Tools/Scripts/webkitpy/layout_tests/port/test.py
index 5df5c2d..b94c378 100644
--- a/Tools/Scripts/webkitpy/layout_tests/port/test.py
+++ b/Tools/Scripts/webkitpy/layout_tests/port/test.py
@@ -33,8 +33,7 @@ from __future__ import with_statement
import time
from webkitpy.common.system import filesystem_mock
-
-from webkitpy.layout_tests.layout_package import test_output
+from webkitpy.tool import mocktool
import base
@@ -51,9 +50,17 @@ class TestInstance:
self.keyboard = False
self.error = ''
self.timeout = False
- self.actual_text = self.base + '-txt\n'
- self.actual_checksum = self.base + '-checksum\n'
- self.actual_image = self.base + '-png\n'
+
+ # The values of each field are treated as raw byte strings. They
+ # will be converted to unicode strings where appropriate using
+ # MockFileSystem.read_text_file().
+ self.actual_text = self.base + '-txt'
+ self.actual_checksum = self.base + '-checksum'
+
+ # We add the '\x8a' for the image file to prevent the value from
+ # being treated as UTF-8 (the character is invalid)
+ self.actual_image = self.base + '\x8a' + '-png'
+
self.expected_text = self.actual_text
self.expected_checksum = self.actual_checksum
self.expected_image = self.actual_image
@@ -84,53 +91,44 @@ class TestList:
def unit_test_list():
tests = TestList()
tests.add('failures/expected/checksum.html',
- actual_checksum='checksum_fail-checksum')
+ actual_checksum='checksum_fail-checksum')
tests.add('failures/expected/crash.html', crash=True)
tests.add('failures/expected/exception.html', exception=True)
tests.add('failures/expected/timeout.html', timeout=True)
tests.add('failures/expected/hang.html', hang=True)
- tests.add('failures/expected/missing_text.html',
- expected_text=None)
+ tests.add('failures/expected/missing_text.html', expected_text=None)
tests.add('failures/expected/image.html',
- actual_image='image_fail-png',
- expected_image='image-png')
+ actual_image='image_fail-png',
+ expected_image='image-png')
tests.add('failures/expected/image_checksum.html',
- actual_checksum='image_checksum_fail-checksum',
- actual_image='image_checksum_fail-png')
- tests.add('failures/expected/keyboard.html',
- keyboard=True)
- tests.add('failures/expected/missing_check.html',
- expected_checksum=None)
- tests.add('failures/expected/missing_image.html',
- expected_image=None)
- tests.add('failures/expected/missing_text.html',
- expected_text=None)
+ actual_checksum='image_checksum_fail-checksum',
+ actual_image='image_checksum_fail-png')
+ tests.add('failures/expected/keyboard.html', keyboard=True)
+ tests.add('failures/expected/missing_check.html', expected_checksum=None)
+ tests.add('failures/expected/missing_image.html', expected_image=None)
+ tests.add('failures/expected/missing_text.html', expected_text=None)
tests.add('failures/expected/newlines_leading.html',
- expected_text="\nfoo\n",
- actual_text="foo\n")
+ expected_text="\nfoo\n", actual_text="foo\n")
tests.add('failures/expected/newlines_trailing.html',
- expected_text="foo\n\n",
- actual_text="foo\n")
+ expected_text="foo\n\n", actual_text="foo\n")
tests.add('failures/expected/newlines_with_excess_CR.html',
- expected_text="foo\r\r\r\n",
- actual_text="foo\n")
- tests.add('failures/expected/text.html',
- actual_text='text_fail-png')
+ expected_text="foo\r\r\r\n", actual_text="foo\n")
+ tests.add('failures/expected/text.html', actual_text='text_fail-png')
tests.add('failures/unexpected/crash.html', crash=True)
tests.add('failures/unexpected/text-image-checksum.html',
- actual_text='text-image-checksum_fail-txt',
- actual_checksum='text-image-checksum_fail-checksum')
+ actual_text='text-image-checksum_fail-txt',
+ actual_checksum='text-image-checksum_fail-checksum')
tests.add('failures/unexpected/timeout.html', timeout=True)
tests.add('http/tests/passes/text.html')
tests.add('http/tests/ssl/text.html')
tests.add('passes/error.html', error='stuff going to stderr')
tests.add('passes/image.html')
tests.add('passes/platform_image.html')
+
# Text output files contain "\r\n" on Windows. This may be
# helpfully filtered to "\r\r\n" by our Python/Cygwin tooling.
tests.add('passes/text.html',
- expected_text='\nfoo\n\n',
- actual_text='\nfoo\r\n\r\r\n')
+ expected_text='\nfoo\n\n', actual_text='\nfoo\r\n\r\r\n')
tests.add('websocket/tests/passes/text.html')
return tests
@@ -184,6 +182,9 @@ WONTFIX SKIP : failures/expected/keyboard.html = CRASH
WONTFIX SKIP : failures/expected/exception.html = CRASH
"""
+ # Add in a file should be ignored by test_files.find().
+ files[LAYOUT_TEST_DIR + 'userscripts/resources/iframe.html'] = 'iframe'
+
fs = filesystem_mock.MockFileSystem(files)
fs._tests = test_list
return fs
@@ -192,30 +193,31 @@ WONTFIX SKIP : failures/expected/exception.html = CRASH
class TestPort(base.Port):
"""Test implementation of the Port interface."""
- def __init__(self, **kwargs):
- # FIXME: what happens if we're not passed in the test filesystem
- # and the tests don't match what's in the filesystem?
- #
- # We'll leave as is for now to avoid unnecessary dependencies while
- # converting all of the unit tests over to using
- # unit_test_filesystem(). If things get out of sync the tests should
- # fail in fairly obvious ways. Eventually we want to just do:
- #
- # assert kwargs['filesystem']._tests
- # self._tests = kwargs['filesystem']._tests
+ def __init__(self, port_name=None, user=None, filesystem=None, **kwargs):
+ if not filesystem:
+ filesystem = unit_test_filesystem()
+
+ assert filesystem._tests
+ self._tests = filesystem._tests
+
+ if not user:
+ user = mocktool.MockUser()
- if 'filesystem' not in kwargs or kwargs['filesystem'] is None:
- kwargs['filesystem'] = unit_test_filesystem()
- self._tests = kwargs['filesystem']._tests
- else:
- self._tests = unit_test_list()
+ if not port_name or port_name == 'test':
+ port_name = 'test-mac'
- kwargs.setdefault('port_name', 'test')
- base.Port.__init__(self, **kwargs)
+ self._expectations_path = LAYOUT_TEST_DIR + '/platform/test/test_expectations.txt'
+ base.Port.__init__(self, port_name=port_name, filesystem=filesystem, user=user,
+ **kwargs)
+
+ def _path_to_driver(self):
+ # This routine shouldn't normally be called, but it is called by
+ # the mock_drt Driver. We return something, but make sure it's useless.
+ return 'junk'
def baseline_path(self):
- return self._filesystem.join(self.layout_tests_dir(), 'platform',
- self.name() + self.version())
+ # We don't bother with a fallback path.
+ return self._filesystem.join(self.layout_tests_dir(), 'platform', self.name())
def baseline_search_path(self):
return [self.baseline_path()]
@@ -223,11 +225,14 @@ class TestPort(base.Port):
def check_build(self, needs_http):
return True
+ def default_configuration(self):
+ return 'Release'
+
def diff_image(self, expected_contents, actual_contents,
diff_filename=None):
diffed = actual_contents != expected_contents
if diffed and diff_filename:
- self._filesystem.write_text_file(diff_filename,
+ self._filesystem.write_binary_file(diff_filename,
"< %s\n---\n> %s\n" % (expected_contents, actual_contents))
return diffed
@@ -261,23 +266,98 @@ class TestPort(base.Port):
def stop_websocket_server(self):
pass
- def test_base_platform_names(self):
- return ('mac', 'win')
-
- def test_expectations(self):
- return self._filesystem.read_text_file(LAYOUT_TEST_DIR + '/platform/test/test_expectations.txt')
+ def path_to_test_expectations_file(self):
+ return self._expectations_path
def test_platform_name(self):
- return 'mac'
+ name_map = {
+ 'test-mac': 'mac',
+ 'test-win': 'win',
+ 'test-win-xp': 'win-xp',
+ }
+ return name_map[self._name]
def test_platform_names(self):
- return self.test_base_platform_names()
+ return ('mac', 'win', 'win-xp')
def test_platform_name_to_name(self, test_platform_name):
- return test_platform_name
+ name_map = {
+ 'mac': 'test-mac',
+ 'win': 'test-win',
+ 'win-xp': 'test-win-xp',
+ }
+ return name_map[test_platform_name]
+
+ # FIXME: These next two routines are copied from base.py with
+ # the calls to path.abspath_to_uri() removed. We shouldn't have
+ # to do this.
+ def filename_to_uri(self, filename):
+ """Convert a test file (which is an absolute path) to a URI."""
+ LAYOUTTEST_HTTP_DIR = "http/tests/"
+ LAYOUTTEST_WEBSOCKET_DIR = "http/tests/websocket/tests/"
+
+ relative_path = self.relative_test_filename(filename)
+ port = None
+ use_ssl = False
+
+ if (relative_path.startswith(LAYOUTTEST_WEBSOCKET_DIR)
+ or relative_path.startswith(LAYOUTTEST_HTTP_DIR)):
+ relative_path = relative_path[len(LAYOUTTEST_HTTP_DIR):]
+ port = 8000
+
+ # Make http/tests/local run as local files. This is to mimic the
+ # logic in run-webkit-tests.
+ #
+ # TODO(dpranke): remove the media reference and the SSL reference?
+ if (port and not relative_path.startswith("local/") and
+ not relative_path.startswith("media/")):
+ if relative_path.startswith("ssl/"):
+ port += 443
+ protocol = "https"
+ else:
+ protocol = "http"
+ return "%s://127.0.0.1:%u/%s" % (protocol, port, relative_path)
+
+ return "file://" + self._filesystem.abspath(filename)
+
+ def uri_to_test_name(self, uri):
+ """Return the base layout test name for a given URI.
+
+ This returns the test name for a given URI, e.g., if you passed in
+ "file:///src/LayoutTests/fast/html/keygen.html" it would return
+ "fast/html/keygen.html".
+
+ """
+ test = uri
+ if uri.startswith("file:///"):
+ prefix = "file://" + self.layout_tests_dir() + "/"
+ return test[len(prefix):]
+
+ if uri.startswith("http://127.0.0.1:8880/"):
+ # websocket tests
+ return test.replace('http://127.0.0.1:8880/', '')
+
+ if uri.startswith("http://"):
+ # regular HTTP test
+ return test.replace('http://127.0.0.1:8000/', 'http/tests/')
+
+ if uri.startswith("https://"):
+ return test.replace('https://127.0.0.1:8443/', 'http/tests/')
+
+ raise NotImplementedError('unknown url type: %s' % uri)
def version(self):
- return ''
+ version_map = {
+ 'test-win-xp': '-xp',
+ 'test-win': '-7',
+ 'test-mac': '-leopard',
+ }
+ return version_map[self._name]
+
+ def test_configuration(self):
+ if not self._test_configuration:
+ self._test_configuration = TestTestConfiguration(self)
+ return self._test_configuration
class TestDriver(base.Driver):
@@ -287,7 +367,7 @@ class TestDriver(base.Driver):
self._port = port
def cmd_line(self):
- return ['None']
+ return [self._port._path_to_driver()]
def poll(self):
return True
@@ -302,13 +382,20 @@ class TestDriver(base.Driver):
raise ValueError('exception from ' + test_name)
if test.hang:
time.sleep((float(test_input.timeout) * 4) / 1000.0)
- return test_output.TestOutput(test.actual_text, test.actual_image,
- test.actual_checksum, test.crash,
- time.time() - start_time, test.timeout,
- test.error)
+ return base.DriverOutput(test.actual_text, test.actual_image,
+ test.actual_checksum, test.crash,
+ time.time() - start_time, test.timeout,
+ test.error)
def start(self):
pass
def stop(self):
pass
+
+
+class TestTestConfiguration(base.TestConfiguration):
+ def all_systems(self):
+ return (('mac', 'leopard', 'x86'),
+ ('win', 'xp', 'x86'),
+ ('win', 'win7', 'x86'))
diff --git a/Tools/Scripts/webkitpy/layout_tests/port/test_files.py b/Tools/Scripts/webkitpy/layout_tests/port/test_files.py
index 41d918f..534462a 100644
--- a/Tools/Scripts/webkitpy/layout_tests/port/test_files.py
+++ b/Tools/Scripts/webkitpy/layout_tests/port/test_files.py
@@ -49,37 +49,47 @@ _supported_file_extensions = set(['.html', '.shtml', '.xml', '.xhtml', '.xhtmlmp
_skipped_directories = set(['.svn', '_svn', 'resources', 'script-tests'])
-def find(port, paths):
- """Finds the set of tests under port.layout_tests_dir().
+def find(port, paths=None):
+ """Finds the set of tests under a given list of sub-paths.
Args:
- paths: a list of command line paths relative to the layout_tests_dir()
- to limit the search to. glob patterns are ok.
+ paths: a list of path expressions relative to port.layout_tests_dir()
+ to search. Glob patterns are ok, as are path expressions with
+ forward slashes on Windows. If paths is empty, we look at
+ everything under the layout_tests_dir().
+ """
+ paths = paths or ['*']
+ filesystem = port._filesystem
+ return normalized_find(filesystem, normalize(filesystem, port.layout_tests_dir(), paths))
+
+
+def normalize(filesystem, base_dir, paths):
+ return [filesystem.normpath(filesystem.join(base_dir, path)) for path in paths]
+
+
+def normalized_find(filesystem, paths):
+ """Finds the set of tests under the list of paths.
+
+ Args:
+ paths: a list of absolute path expressions to search.
+ Glob patterns are ok.
"""
- fs = port._filesystem
gather_start_time = time.time()
paths_to_walk = set()
- # if paths is empty, provide a pre-defined list.
- if paths:
- _log.debug("Gathering tests from: %s relative to %s" % (paths, port.layout_tests_dir()))
- for path in paths:
- # If there's an * in the name, assume it's a glob pattern.
- path = fs.join(port.layout_tests_dir(), path)
- if path.find('*') > -1:
- filenames = fs.glob(path)
- paths_to_walk.update(filenames)
- else:
- paths_to_walk.add(path)
- else:
- _log.debug("Gathering tests from: %s" % port.layout_tests_dir())
- paths_to_walk.add(port.layout_tests_dir())
+ for path in paths:
+ # If there's an * in the name, assume it's a glob pattern.
+ if path.find('*') > -1:
+ filenames = filesystem.glob(path)
+ paths_to_walk.update(filenames)
+ else:
+ paths_to_walk.add(path)
# FIXME: I'm not sure there's much point in this being a set. A list would
# probably be faster.
test_files = set()
for path in paths_to_walk:
- files = fs.files_under(path, _skipped_directories, _is_test_file)
+ files = filesystem.files_under(path, _skipped_directories, _is_test_file)
test_files.update(set(files))
gather_time = time.time() - gather_start_time
@@ -88,10 +98,10 @@ def find(port, paths):
return test_files
-def _has_supported_extension(fs, filename):
+def _has_supported_extension(filesystem, filename):
"""Return true if filename is one of the file extensions we want to run a
test on."""
- extension = fs.splitext(filename)[1]
+ extension = filesystem.splitext(filename)[1]
return extension in _supported_file_extensions
@@ -104,7 +114,7 @@ def _is_reference_html_file(filename):
return False
-def _is_test_file(fs, dirname, filename):
+def _is_test_file(filesystem, dirname, filename):
"""Return true if the filename points to a test file."""
- return (_has_supported_extension(fs, filename) and
+ return (_has_supported_extension(filesystem, filename) and
not _is_reference_html_file(filename))
diff --git a/Tools/Scripts/webkitpy/layout_tests/port/test_files_unittest.py b/Tools/Scripts/webkitpy/layout_tests/port/test_files_unittest.py
index a68950a..a29ba49 100644
--- a/Tools/Scripts/webkitpy/layout_tests/port/test_files_unittest.py
+++ b/Tools/Scripts/webkitpy/layout_tests/port/test_files_unittest.py
@@ -26,44 +26,41 @@
# (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
import unittest
-import base
+from webkitpy.layout_tests.port import test
import test_files
-
class TestFilesTest(unittest.TestCase):
def test_find_no_paths_specified(self):
- port = base.Port()
+ port = test.TestPort()
layout_tests_dir = port.layout_tests_dir()
- port.layout_tests_dir = lambda: port._filesystem.join(layout_tests_dir,
- 'fast', 'html')
tests = test_files.find(port, [])
- self.assertNotEqual(tests, 0)
+ self.assertNotEqual(len(tests), 0)
def test_find_one_test(self):
- port = base.Port()
- # This is just a test picked at random but known to exist.
- tests = test_files.find(port, ['fast/html/keygen.html'])
+ port = test.TestPort()
+ tests = test_files.find(port, ['failures/expected/image.html'])
self.assertEqual(len(tests), 1)
def test_find_glob(self):
- port = base.Port()
- tests = test_files.find(port, ['fast/html/key*'])
- self.assertEqual(len(tests), 1)
+ port = test.TestPort()
+ tests = test_files.find(port, ['failures/expected/im*'])
+ self.assertEqual(len(tests), 2)
def test_find_with_skipped_directories(self):
- port = base.Port()
+ port = test.TestPort()
tests = port.tests('userscripts')
- self.assertTrue('userscripts/resources/frame1.html' not in tests)
+ self.assertTrue('userscripts/resources/iframe.html' not in tests)
def test_find_with_skipped_directories_2(self):
- port = base.Port()
+ port = test.TestPort()
tests = test_files.find(port, ['userscripts/resources'])
self.assertEqual(tests, set([]))
def test_is_test_file(self):
- port = base.Port()
+ port = test.TestPort()
fs = port._filesystem
self.assertTrue(test_files._is_test_file(fs, '', 'foo.html'))
self.assertTrue(test_files._is_test_file(fs, '', 'foo.shtml'))
@@ -72,5 +69,33 @@ class TestFilesTest(unittest.TestCase):
self.assertFalse(test_files._is_test_file(fs, '', 'foo-expected-mismatch.html'))
+class MockWinFileSystem(object):
+ def join(self, *paths):
+ return '\\'.join(paths)
+
+ def normpath(self, path):
+ return path.replace('/', '\\')
+
+
+class TestWinNormalize(unittest.TestCase):
+ def assert_filesystem_normalizes(self, filesystem):
+ self.assertEquals(test_files.normalize(filesystem, "c:\\foo",
+ ['fast/html', 'fast/canvas/*', 'compositing/foo.html']),
+ ['c:\\foo\\fast\html', 'c:\\foo\\fast\canvas\*', 'c:\\foo\compositing\\foo.html'])
+
+ def test_mocked_win(self):
+ # This tests test_files.normalize, using portable behavior emulating
+ # what we think Windows is supposed to do. This test will run on all
+ # platforms.
+ self.assert_filesystem_normalizes(MockWinFileSystem())
+
+ def test_win(self):
+ # This tests the actual windows platform, to ensure we get the same
+ # results that we get in test_mocked_win().
+ if sys.platform != 'win':
+ return
+ self.assert_filesystem_normalizes(FileSystem())
+
+
if __name__ == '__main__':
unittest.main()
diff --git a/Tools/Scripts/webkitpy/layout_tests/port/webkit.py b/Tools/Scripts/webkitpy/layout_tests/port/webkit.py
index 577acd4..65a047d 100644
--- a/Tools/Scripts/webkitpy/layout_tests/port/webkit.py
+++ b/Tools/Scripts/webkitpy/layout_tests/port/webkit.py
@@ -40,10 +40,9 @@ import sys
import time
import webbrowser
-import webkitpy.common.system.ospath as ospath
-import webkitpy.layout_tests.layout_package.test_output as test_output
-import webkitpy.layout_tests.port.base as base
-import webkitpy.layout_tests.port.server_process as server_process
+from webkitpy.common.system import ospath
+from webkitpy.layout_tests.port import base
+from webkitpy.layout_tests.port import server_process
_log = logging.getLogger("webkitpy.layout_tests.port.webkit")
@@ -57,7 +56,8 @@ class WebKitPort(base.Port):
# FIXME: disable pixel tests until they are run by default on the
# build machines.
- self.set_option_default('pixel_tests', False)
+ if not hasattr(self._options, "pixel_tests") or self._options.pixel_tests == None:
+ self._options.pixel_tests = False
def baseline_path(self):
return self._webkit_baseline_path(self._name)
@@ -120,9 +120,9 @@ class WebKitPort(base.Port):
return self._diff_image_reply(sp, diff_filename)
def _diff_image_request(self, expected_contents, actual_contents):
- # FIXME: use self.get_option('tolerance') and
- # self.set_option_default('tolerance', 0.1) once that behaves correctly
- # with default values.
+ # FIXME: There needs to be a more sane way of handling default
+ # values for options so that you can distinguish between a default
+ # value of None and a default value that wasn't set.
if self.get_option('tolerance') is not None:
tolerance = self.get_option('tolerance')
else:
@@ -159,7 +159,7 @@ class WebKitPort(base.Port):
if m.group(2) == 'passed':
result = False
elif output and diff_filename:
- self._filesystem.write_text_file(diff_filename, output)
+ self._filesystem.write_binary_file(diff_filename, output)
elif sp.timed_out:
_log.error("ImageDiff timed out")
elif sp.crashed:
@@ -179,11 +179,6 @@ class WebKitPort(base.Port):
def create_driver(self, worker_number):
return WebKitDriver(self, worker_number)
- def test_base_platform_names(self):
- # At the moment we don't use test platform names, but we have
- # to return something.
- return ('mac', 'win')
-
def _tests_for_other_platforms(self):
raise NotImplementedError('WebKitPort._tests_for_other_platforms')
# The original run-webkit-tests builds up a "whitelist" of tests to
@@ -283,9 +278,9 @@ class WebKitPort(base.Port):
unsupported_feature_tests = self._skipped_tests_for_unsupported_features()
return disabled_feature_tests + webarchive_tests + unsupported_feature_tests
- def _tests_from_skipped_file(self, skipped_file):
+ def _tests_from_skipped_file_contents(self, skipped_file_contents):
tests_to_skip = []
- for line in skipped_file.readlines():
+ for line in skipped_file_contents.split('\n'):
line = line.strip()
if line.startswith('#') or not len(line):
continue
@@ -301,7 +296,8 @@ class WebKitPort(base.Port):
if not self._filesystem.exists(filename):
_log.warn("Failed to open Skipped file: %s" % filename)
continue
- skipped_file = self._filesystem.read_text_file(filename)
+ skipped_file_contents = self._filesystem.read_text_file(filename)
+ tests_to_skip.extend(self._tests_from_skipped_file_contents(skipped_file_contents))
return tests_to_skip
def test_expectations(self):
@@ -335,8 +331,7 @@ class WebKitPort(base.Port):
return self._name + self.version()
def test_platform_names(self):
- return self.test_base_platform_names() + (
- 'mac-tiger', 'mac-leopard', 'mac-snowleopard')
+ return ('mac', 'win', 'mac-tiger', 'mac-leopard', 'mac-snowleopard')
def _build_path(self, *comps):
return self._filesystem.join(self._config.build_directory(
@@ -409,15 +404,15 @@ class WebKitDriver(base.Driver):
return
# FIXME: This function is huge.
- def run_test(self, test_input):
- uri = self._port.filename_to_uri(test_input.filename)
+ def run_test(self, driver_input):
+ uri = self._port.filename_to_uri(driver_input.filename)
if uri.startswith("file:///"):
command = uri[7:]
else:
command = uri
- if test_input.image_hash:
- command += "'" + test_input.image_hash
+ if driver_input.image_hash:
+ command += "'" + driver_input.image_hash
command += "\n"
start_time = time.time()
@@ -428,7 +423,7 @@ class WebKitDriver(base.Driver):
output = str() # Use a byte array for output, even though it should be UTF-8.
image = str()
- timeout = int(test_input.timeout) / 1000.0
+ timeout = int(driver_input.timeout) / 1000.0
deadline = time.time() + timeout
line = self._server_process.read_line(timeout)
while (not self._server_process.timed_out
@@ -475,11 +470,11 @@ class WebKitDriver(base.Driver):
# FIXME: This seems like the wrong section of code to be doing
# this reset in.
self._server_process.error = ""
- return test_output.TestOutput(output, image, actual_image_hash,
- self._server_process.crashed,
- time.time() - start_time,
- self._server_process.timed_out,
- error)
+ return base.DriverOutput(output, image, actual_image_hash,
+ self._server_process.crashed,
+ time.time() - start_time,
+ self._server_process.timed_out,
+ error)
def stop(self):
if self._server_process:
diff --git a/Tools/Scripts/webkitpy/layout_tests/port/webkit_unittest.py b/Tools/Scripts/webkitpy/layout_tests/port/webkit_unittest.py
index 7b68310..c72a411 100644
--- a/Tools/Scripts/webkitpy/layout_tests/port/webkit_unittest.py
+++ b/Tools/Scripts/webkitpy/layout_tests/port/webkit_unittest.py
@@ -1,5 +1,6 @@
#!/usr/bin/env python
# Copyright (C) 2010 Gabor Rapcsanyi <rgabor@inf.u-szeged.hu>, University of Szeged
+# Copyright (C) 2010 Google Inc. All rights reserved.
#
# All rights reserved.
#
@@ -26,13 +27,19 @@
import unittest
+from webkitpy.common.system import filesystem_mock
+
from webkitpy.layout_tests.port.webkit import WebKitPort
class TestWebKitPort(WebKitPort):
- def __init__(self, symbol_list=None, feature_list=None):
+ def __init__(self, symbol_list=None, feature_list=None,
+ expectations_file=None, skips_file=None, **kwargs):
self.symbol_list = symbol_list
self.feature_list = feature_list
+ self.expectations_file = expectations_file
+ self.skips_file = skips_file
+ WebKitPort.__init__(self, **kwargs)
def _runtime_feature_list(self):
return self.feature_list
@@ -46,7 +53,14 @@ class TestWebKitPort(WebKitPort):
def _tests_for_disabled_features(self):
return ["accessibility", ]
+ def path_to_test_expectations_file(self):
+ if self.expectations_file:
+ return self.expectations_file
+ return WebKitPort.path_to_test_expectations_file(self)
+
def _skipped_file_paths(self):
+ if self.skips_file:
+ return [self.skips_file]
return []
class WebKitPortTest(unittest.TestCase):
@@ -66,3 +80,23 @@ class WebKitPortTest(unittest.TestCase):
def test_skipped_layout_tests(self):
self.assertEqual(TestWebKitPort(None, None).skipped_layout_tests(),
set(["media", "accessibility"]))
+
+ def test_test_expectations(self):
+ # Check that we read both the expectations file and anything in a
+ # Skipped file, and that we include the feature and platform checks.
+ files = {
+ '/tmp/test_expectations.txt': 'BUG_TESTEXPECTATIONS SKIP : fast/html/article-element.html = FAIL\n',
+ '/tmp/Skipped': 'fast/html/keygen.html',
+ }
+ mock_fs = filesystem_mock.MockFileSystem(files)
+ port = TestWebKitPort(expectations_file='/tmp/test_expectations.txt',
+ skips_file='/tmp/Skipped', filesystem=mock_fs)
+ self.assertEqual(port.test_expectations(),
+ """BUG_TESTEXPECTATIONS SKIP : fast/html/article-element.html = FAIL
+BUG_SKIPPED SKIP : fast/html/keygen.html = FAIL
+BUG_SKIPPED SKIP : media = FAIL
+BUG_SKIPPED SKIP : accessibility = FAIL""")
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/Tools/Scripts/webkitpy/layout_tests/port/websocket_server.py b/Tools/Scripts/webkitpy/layout_tests/port/websocket_server.py
index 926bc04..713ad21 100644
--- a/Tools/Scripts/webkitpy/layout_tests/port/websocket_server.py
+++ b/Tools/Scripts/webkitpy/layout_tests/port/websocket_server.py
@@ -73,7 +73,7 @@ def url_is_alive(url):
wait_time = 10
while wait_time > 0:
try:
- response = urllib.urlopen(url)
+ response = urllib.urlopen(url, proxies={})
# Server is up and responding.
return True
except IOError:
diff --git a/Tools/Scripts/webkitpy/layout_tests/rebaseline_chromium_webkit_tests.py b/Tools/Scripts/webkitpy/layout_tests/rebaseline_chromium_webkit_tests.py
index c852186..567975c 100644
--- a/Tools/Scripts/webkitpy/layout_tests/rebaseline_chromium_webkit_tests.py
+++ b/Tools/Scripts/webkitpy/layout_tests/rebaseline_chromium_webkit_tests.py
@@ -47,18 +47,17 @@ import optparse
import re
import sys
import time
-import urllib
-import zipfile
from webkitpy.common.checkout import scm
+from webkitpy.common.system import zipfileset
from webkitpy.common.system import path
+from webkitpy.common.system import urlfetcher
from webkitpy.common.system.executive import ScriptError
-import port
-from layout_package import test_expectations
+from webkitpy.layout_tests import port
+from webkitpy.layout_tests.layout_package import test_expectations
-_log = logging.getLogger("webkitpy.layout_tests."
- "rebaseline_chromium_webkit_tests")
+_log = logging.getLogger(__name__)
BASELINE_SUFFIXES = ['.txt', '.png', '.checksum']
REBASELINE_PLATFORM_ORDER = ['mac', 'win', 'win-xp', 'win-vista', 'linux']
@@ -142,7 +141,7 @@ class Rebaseliner(object):
REVISION_REGEX = r'<a href=\"(\d+)/\">'
- def __init__(self, running_port, target_port, platform, options):
+ def __init__(self, running_port, target_port, platform, options, url_fetcher, zip_factory, scm):
"""
Args:
running_port: the Port the script is running on.
@@ -150,14 +149,20 @@ class Rebaseliner(object):
configuration information like the test_expectations.txt
file location and the list of test platforms.
platform: the test platform to rebaseline
- options: the command-line options object."""
+ options: the command-line options object.
+ url_fetcher: object that can fetch objects from URLs
+ zip_factory: optional object that can fetch zip files from URLs
+ scm: scm object for adding new baselines
+ """
self._platform = platform
self._options = options
self._port = running_port
self._filesystem = running_port._filesystem
self._target_port = target_port
+
self._rebaseline_port = port.get(
- self._target_port.test_platform_name_to_name(platform), options)
+ self._target_port.test_platform_name_to_name(platform), options,
+ filesystem=self._filesystem)
self._rebaselining_tests = []
self._rebaselined_tests = []
@@ -170,10 +175,11 @@ class Rebaseliner(object):
test_expectations.TestExpectations(self._rebaseline_port,
None,
expectations_str,
- self._platform,
- False,
+ self._rebaseline_port.test_configuration(),
False)
- self._scm = scm.default_scm()
+ self._url_fetcher = url_fetcher
+ self._zip_factory = zip_factory
+ self._scm = scm
def run(self, backup):
"""Run rebaseline process."""
@@ -192,8 +198,11 @@ class Rebaseliner(object):
log_dashed_string('Extracting and adding new baselines',
self._platform)
if not self._extract_and_add_new_baselines(archive_file):
+ archive_file.close()
return False
+ archive_file.close()
+
log_dashed_string('Updating rebaselined tests in file',
self._platform)
self._update_rebaselined_tests_in_file(backup)
@@ -254,9 +263,7 @@ class Rebaseliner(object):
_log.debug('Url to retrieve revision: "%s"', url)
- f = urllib.urlopen(url)
- content = f.read()
- f.close()
+ content = self._url_fetcher.fetch(url)
revisions = re.findall(self.REVISION_REGEX, content)
if not revisions:
@@ -313,33 +320,24 @@ class Rebaseliner(object):
return archive_url
def _download_buildbot_archive(self):
- """Download layout test archive file from buildbot.
-
- Returns:
- True if download succeeded or
- False otherwise.
- """
-
+ """Download layout test archive file from buildbot and return a handle to it."""
url = self._get_archive_url()
if url is None:
return None
- fn = urllib.urlretrieve(url)[0]
- _log.info('Archive downloaded and saved to file: "%s"', fn)
- return fn
+ archive_file = zipfileset.ZipFileSet(url, filesystem=self._filesystem,
+ zip_factory=self._zip_factory)
+ _log.info('Archive downloaded')
+ return archive_file
- def _extract_and_add_new_baselines(self, archive_file):
- """Extract new baselines from archive and add them to SVN repository.
-
- Args:
- archive_file: full path to the archive file.
+ def _extract_and_add_new_baselines(self, zip_file):
+ """Extract new baselines from the zip file and add them to SVN repository.
Returns:
List of tests that have been rebaselined or
None on failure.
"""
- zip_file = zipfile.ZipFile(archive_file, 'r')
zip_namelist = zip_file.namelist()
_log.debug('zip file namelist:')
@@ -419,7 +417,6 @@ class Rebaseliner(object):
test_no += 1
zip_file.close()
- self._filesystem.remove(archive_file)
return self._rebaselined_tests
@@ -857,18 +854,9 @@ def parse_options(args):
return (options, target_options)
-def main():
- """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:
- # location of the expectations file, names of ports to rebaseline, etc.
- # |port_obj| is used for runtime functionality like actually diffing
- # Then we create a rebaselining port to actual find and manage the
- # baselines.
- target_port_obj = port.get(None, target_options)
+def main(args):
+ """Bootstrap function that sets up the object references we need and calls real_main()."""
+ options, target_options = parse_options(args)
# Set up our logging format.
log_level = logging.INFO
@@ -879,20 +867,53 @@ def main():
'%(levelname)s %(message)s'),
datefmt='%y%m%d %H:%M:%S')
+ target_port_obj = port.get(None, target_options)
host_port_obj = get_host_port_object(options)
- if not host_port_obj:
- sys.exit(1)
+ if not host_port_obj or not target_port_obj:
+ return 1
+
+ url_fetcher = urlfetcher.UrlFetcher(host_port_obj._filesystem)
+ scm_obj = scm.default_scm()
+
+ # We use the default zip factory method.
+ zip_factory = None
+
+ return real_main(options, target_options, host_port_obj, target_port_obj, url_fetcher,
+ zip_factory, scm_obj)
+
+def real_main(options, target_options, host_port_obj, target_port_obj, url_fetcher,
+ zip_factory, scm_obj):
+ """Main function to produce new baselines. The Rebaseliner object uses two
+ different Port objects - one to represent the machine the object is running
+ on, and one to represent the port whose expectations are being updated.
+ E.g., you can run the script on a mac and rebaseline the 'win' port.
+
+ Args:
+ options: command-line argument used for the host_port_obj (see below)
+ target_options: command_line argument used for the target_port_obj.
+ This object may have slightly different values than |options|.
+ host_port_obj: a Port object for the platform the script is running
+ on. This is used to produce image and text diffs, mostly, and
+ is usually acquired from get_host_port_obj().
+ target_port_obj: a Port obj representing the port getting rebaselined.
+ This is used to find the expectations file, the baseline paths,
+ etc.
+ url_fetcher: object used to download the build archives from the bots
+ zip_factory: factory function used to create zip file objects for
+ the archives.
+ scm_obj: object used to add new baselines to the source control system.
+ """
# Verify 'platforms' option is valid.
if not options.platforms:
_log.error('Invalid "platforms" option. --platforms must be '
'specified in order to rebaseline.')
- sys.exit(1)
+ return 1
platforms = [p.strip().lower() for p in options.platforms.split(',')]
for platform in platforms:
if not platform in REBASELINE_PLATFORM_ORDER:
_log.error('Invalid platform: "%s"' % (platform))
- sys.exit(1)
+ return 1
# Adjust the platform order so rebaseline tool is running at the order of
# 'mac', 'win' and 'linux'. This is in same order with layout test baseline
@@ -909,7 +930,8 @@ def main():
backup = options.backup
for platform in rebaseline_platforms:
rebaseliner = Rebaseliner(host_port_obj, target_port_obj,
- platform, options)
+ platform, options, url_fetcher, zip_factory,
+ scm_obj)
_log.info('')
log_dashed_string('Rebaseline started', platform)
@@ -934,7 +956,8 @@ def main():
html_generator.show_html()
log_dashed_string('Rebaselining result comparison done', None)
- sys.exit(0)
+ return 0
+
if '__main__' == __name__:
- main()
+ sys.exit(main(sys.argv[1:]))
diff --git a/Tools/Scripts/webkitpy/layout_tests/rebaseline_chromium_webkit_tests_unittest.py b/Tools/Scripts/webkitpy/layout_tests/rebaseline_chromium_webkit_tests_unittest.py
index 50c0204..730220b 100644
--- a/Tools/Scripts/webkitpy/layout_tests/rebaseline_chromium_webkit_tests_unittest.py
+++ b/Tools/Scripts/webkitpy/layout_tests/rebaseline_chromium_webkit_tests_unittest.py
@@ -32,11 +32,14 @@
import unittest
from webkitpy.tool import mocktool
+from webkitpy.common.system import urlfetcher_mock
from webkitpy.common.system import filesystem_mock
+from webkitpy.common.system import zipfileset_mock
+from webkitpy.common.system import outputcapture
from webkitpy.common.system.executive import Executive, ScriptError
-import port
-import rebaseline_chromium_webkit_tests
+from webkitpy.layout_tests import port
+from webkitpy.layout_tests import rebaseline_chromium_webkit_tests
class MockPort(object):
@@ -53,6 +56,57 @@ def get_mock_get(config_expectations):
return mock_get
+ARCHIVE_URL = 'http://localhost/layout_test_results'
+
+
+def test_options():
+ return mocktool.MockOptions(configuration=None,
+ backup=False,
+ html_directory='/tmp',
+ archive_url=ARCHIVE_URL,
+ force_archive_url=None,
+ webkit_canary=True,
+ use_drt=False,
+ target_platform='chromium',
+ verbose=False,
+ quiet=False,
+ platforms='mac,win,win-xp')
+
+
+def test_host_port_and_filesystem(options, expectations):
+ filesystem = port.unit_test_filesystem()
+ host_port_obj = port.get('test', options, filesystem=filesystem,
+ user=mocktool.MockUser())
+
+ expectations_path = host_port_obj.path_to_test_expectations_file()
+ filesystem.write_text_file(expectations_path, expectations)
+ return (host_port_obj, filesystem)
+
+
+def test_url_fetcher(filesystem):
+ urls = {
+ ARCHIVE_URL + '/Webkit_Mac10_5/': '<a href="1/"><a href="2/">',
+ ARCHIVE_URL + '/Webkit_Win/': '<a href="1/">',
+ }
+ return urlfetcher_mock.make_fetcher_cls(urls)(filesystem)
+
+
+def test_zip_factory():
+ ziphashes = {
+ ARCHIVE_URL + '/Webkit_Mac10_5/2/layout-test-results.zip': {
+ 'layout-test-results/failures/expected/image-actual.txt': 'new-image-txt',
+ 'layout-test-results/failures/expected/image-actual.checksum': 'new-image-checksum',
+ 'layout-test-results/failures/expected/image-actual.png': 'new-image-png',
+ },
+ ARCHIVE_URL + '/Webkit_Win/1/layout-test-results.zip': {
+ 'layout-test-results/failures/expected/image-actual.txt': 'win-image-txt',
+ 'layout-test-results/failures/expected/image-actual.checksum': 'win-image-checksum',
+ 'layout-test-results/failures/expected/image-actual.png': 'win-image-png',
+ },
+ }
+ return zipfileset_mock.make_factory(ziphashes)
+
+
class TestGetHostPortObject(unittest.TestCase):
def assert_result(self, release_present, debug_present, valid_port_obj):
# Tests whether we get a valid port object returned when we claim
@@ -60,9 +114,8 @@ class TestGetHostPortObject(unittest.TestCase):
port.get = get_mock_get({'Release': release_present,
'Debug': debug_present})
options = mocktool.MockOptions(configuration=None,
- html_directory=None)
- port_obj = rebaseline_chromium_webkit_tests.get_host_port_object(
- options)
+ html_directory='/tmp')
+ port_obj = rebaseline_chromium_webkit_tests.get_host_port_object(options)
if valid_port_obj:
self.assertNotEqual(port_obj, None)
else:
@@ -84,18 +137,7 @@ class TestGetHostPortObject(unittest.TestCase):
port.get = old_get
-class TestRebaseliner(unittest.TestCase):
- def make_rebaseliner(self):
- options = mocktool.MockOptions(configuration=None,
- html_directory=None)
- filesystem = filesystem_mock.MockFileSystem()
- host_port_obj = port.get('test', options, filesystem=filesystem)
- target_options = options
- target_port_obj = port.get('test', target_options, filesystem=filesystem)
- platform = 'test'
- return rebaseline_chromium_webkit_tests.Rebaseliner(
- host_port_obj, target_port_obj, platform, options)
-
+class TestOptions(unittest.TestCase):
def test_parse_options(self):
(options, target_options) = rebaseline_chromium_webkit_tests.parse_options([])
self.assertTrue(target_options.chromium)
@@ -105,39 +147,113 @@ class TestRebaseliner(unittest.TestCase):
self.assertFalse(hasattr(target_options, 'chromium'))
self.assertEqual(options.tolerance, 0)
+
+class TestRebaseliner(unittest.TestCase):
+ def make_rebaseliner(self, expectations):
+ options = test_options()
+ host_port_obj, filesystem = test_host_port_and_filesystem(options, expectations)
+
+ target_options = options
+ target_port_obj = port.get('test', target_options,
+ filesystem=filesystem)
+ target_port_obj._expectations = expectations
+ platform = target_port_obj.test_platform_name()
+
+ url_fetcher = test_url_fetcher(filesystem)
+ zip_factory = test_zip_factory()
+ mock_scm = mocktool.MockSCM()
+ rebaseliner = rebaseline_chromium_webkit_tests.Rebaseliner(host_port_obj,
+ target_port_obj, platform, options, url_fetcher, zip_factory, mock_scm)
+ return rebaseliner, filesystem
+
def test_noop(self):
# this method tests that was can at least instantiate an object, even
# if there is nothing to do.
- rebaseliner = self.make_rebaseliner()
- self.assertNotEqual(rebaseliner, None)
+ rebaseliner, filesystem = self.make_rebaseliner("")
+ rebaseliner.run(False)
+ self.assertEqual(len(filesystem.written_files), 1)
+
+ def test_one_platform(self):
+ rebaseliner, filesystem = self.make_rebaseliner(
+ "BUGX REBASELINE MAC : failures/expected/image.html = IMAGE")
+ rebaseliner.run(False)
+ # We expect to have written 12 files over the course of this rebaseline:
+ # *) 3 files in /__im_tmp for the extracted archive members
+ # *) 3 new baselines under '/test.checkout/LayoutTests'
+ # *) 4 files in /tmp for the new and old baselines in the result file
+ # (-{old,new}.{txt,png}
+ # *) 1 text diff in /tmp for the result file (-diff.txt). We don't
+ # create image diffs (FIXME?) and don't display the checksums.
+ # *) 1 updated test_expectations file
+ self.assertEqual(len(filesystem.written_files), 12)
+ self.assertEqual(filesystem.files['/test.checkout/LayoutTests/platform/test/test_expectations.txt'], '')
+ self.assertEqual(filesystem.files['/test.checkout/LayoutTests/platform/test-mac/failures/expected/image-expected.checksum'], 'new-image-checksum')
+ self.assertEqual(filesystem.files['/test.checkout/LayoutTests/platform/test-mac/failures/expected/image-expected.png'], 'new-image-png')
+ self.assertEqual(filesystem.files['/test.checkout/LayoutTests/platform/test-mac/failures/expected/image-expected.txt'], 'new-image-txt')
+
+ def test_all_platforms(self):
+ rebaseliner, filesystem = self.make_rebaseliner(
+ "BUGX REBASELINE : failures/expected/image.html = IMAGE")
+ rebaseliner.run(False)
+ # See comment in test_one_platform for an explanation of the 12 written tests.
+ # Note that even though the rebaseline is marked for all platforms, each
+ # rebaseliner only ever does one.
+ self.assertEqual(len(filesystem.written_files), 12)
+ self.assertEqual(filesystem.files['/test.checkout/LayoutTests/platform/test/test_expectations.txt'],
+ 'BUGX REBASELINE WIN : failures/expected/image.html = IMAGE\n'
+ 'BUGX REBASELINE WIN-XP : failures/expected/image.html = IMAGE\n')
+ self.assertEqual(filesystem.files['/test.checkout/LayoutTests/platform/test-mac/failures/expected/image-expected.checksum'], 'new-image-checksum')
+ self.assertEqual(filesystem.files['/test.checkout/LayoutTests/platform/test-mac/failures/expected/image-expected.png'], 'new-image-png')
+ self.assertEqual(filesystem.files['/test.checkout/LayoutTests/platform/test-mac/failures/expected/image-expected.txt'], 'new-image-txt')
def test_diff_baselines_txt(self):
- rebaseliner = self.make_rebaseliner()
- output = rebaseliner._port.expected_text(
- rebaseliner._port._filesystem.join(rebaseliner._port.layout_tests_dir(),
- 'passes/text.html'))
+ rebaseliner, filesystem = self.make_rebaseliner("")
+ port = rebaseliner._port
+ output = port.expected_text(
+ port._filesystem.join(port.layout_tests_dir(), 'passes/text.html'))
self.assertFalse(rebaseliner._diff_baselines(output, output,
is_image=False))
def test_diff_baselines_png(self):
- rebaseliner = self.make_rebaseliner()
- image = rebaseliner._port.expected_image(
- rebaseliner._port._filesystem.join(rebaseliner._port.layout_tests_dir(),
- 'passes/image.html'))
+ rebaseliner, filesystem = self.make_rebaseliner('')
+ port = rebaseliner._port
+ image = port.expected_image(
+ port._filesystem.join(port.layout_tests_dir(), 'passes/image.html'))
self.assertFalse(rebaseliner._diff_baselines(image, image,
is_image=True))
+class TestRealMain(unittest.TestCase):
+ def test_all_platforms(self):
+ expectations = "BUGX REBASELINE : failures/expected/image.html = IMAGE"
+
+ options = test_options()
+
+ host_port_obj, filesystem = test_host_port_and_filesystem(options, expectations)
+ url_fetcher = test_url_fetcher(filesystem)
+ zip_factory = test_zip_factory()
+ mock_scm = mocktool.MockSCM()
+ oc = outputcapture.OutputCapture()
+ oc.capture_output()
+ rebaseline_chromium_webkit_tests.real_main(options, options, host_port_obj,
+ host_port_obj, url_fetcher, zip_factory, mock_scm)
+ oc.restore_output()
+
+ # We expect to have written 35 files over the course of this rebaseline:
+ # *) 11 files * 3 ports for the new baselines and the diffs (see breakdown
+ # under test_one_platform, above)
+ # *) the updated test_expectations file
+ # *) the rebaseline results html file
+ self.assertEqual(len(filesystem.written_files), 35)
+ self.assertEqual(filesystem.files['/test.checkout/LayoutTests/platform/test/test_expectations.txt'], '')
+
+
class TestHtmlGenerator(unittest.TestCase):
def make_generator(self, files, tests):
options = mocktool.MockOptions(configuration=None, html_directory='/tmp')
- host_port = port.get('test', options, filesystem=filesystem_mock.MockFileSystem(files))
- generator = rebaseline_chromium_webkit_tests.HtmlGenerator(
- host_port,
- target_port=None,
- options=options,
- platforms=['mac'],
- rebaselining_tests=tests)
+ host_port = port.get('test', options, filesystem=port.unit_test_filesystem(files))
+ generator = rebaseline_chromium_webkit_tests.HtmlGenerator(host_port,
+ target_port=None, options=options, platforms=['mac'], rebaselining_tests=tests)
return generator, host_port
def test_generate_baseline_links(self):
diff --git a/Tools/Scripts/webkitpy/layout_tests/run_webkit_tests.py b/Tools/Scripts/webkitpy/layout_tests/run_webkit_tests.py
index 17b6e89..2d55b93 100755
--- a/Tools/Scripts/webkitpy/layout_tests/run_webkit_tests.py
+++ b/Tools/Scripts/webkitpy/layout_tests/run_webkit_tests.py
@@ -30,8 +30,6 @@
"""Run layout tests."""
-from __future__ import with_statement
-
import errno
import logging
import optparse
@@ -41,6 +39,7 @@ import sys
from layout_package import printing
from layout_package import test_runner
+from layout_package import test_runner2
from webkitpy.common.system import user
from webkitpy.thirdparty import simplejson
@@ -89,7 +88,11 @@ def run(port, options, args, regular_output=sys.stderr,
# in a try/finally to ensure that we clean up the logging configuration.
num_unexpected_results = -1
try:
- runner = test_runner.TestRunner(port, options, printer)
+ if options.worker_model in ('inline', 'threads', 'processes'):
+ runner = test_runner2.TestRunner2(port, options, printer)
+ else:
+ runner = test_runner.TestRunner(port, options, printer)
+
runner._print_config()
printer.print_update("Collecting tests ...")
@@ -100,11 +103,11 @@ def run(port, options, args, regular_output=sys.stderr,
return -1
raise
- printer.print_update("Parsing expectations ...")
if options.lint_test_files:
return runner.lint()
- runner.parse_expectations(port.test_platform_name(),
- options.configuration == 'Debug')
+
+ printer.print_update("Parsing expectations ...")
+ runner.parse_expectations()
printer.print_update("Checking build ...")
if not port.check_build(runner.needs_http()):
@@ -128,9 +131,12 @@ def _set_up_derived_options(port_obj, options):
# We return a list of warnings to print after the printer is initialized.
warnings = []
- if options.worker_model == 'old-inline':
+ if options.worker_model is None:
+ options.worker_model = port_obj.default_worker_model()
+
+ if options.worker_model in ('inline', 'old-inline'):
if options.child_processes and int(options.child_processes) > 1:
- warnings.append("--worker-model=old-inline overrides --child-processes")
+ warnings.append("--worker-model=%s overrides --child-processes" % options.worker_model)
options.child_processes = "1"
if not options.child_processes:
options.child_processes = os.environ.get("WEBKIT_TEST_CHILD_PROCESSES",
@@ -226,9 +232,6 @@ def parse_args(args=None):
optparse.make_option("--nocheck-sys-deps", action="store_true",
default=False,
help="Don't check the system dependencies (themes)"),
- optparse.make_option("--use-test-shell", action="store_true",
- default=False,
- help="Use test_shell instead of DRT"),
optparse.make_option("--accelerated-compositing",
action="store_true",
help="Use hardware-accelated compositing for rendering"),
@@ -368,8 +371,8 @@ def parse_args(args=None):
help="Number of DumpRenderTrees to run in parallel."),
# FIXME: Display default number of child processes that will run.
optparse.make_option("--worker-model", action="store",
- default="old-threads", help=("controls worker model. Valid values "
- "are 'old-inline', 'old-threads'.")),
+ default=None, help=("controls worker model. Valid values are 'old-inline', "
+ "'old-threads', 'inline', 'threads', and 'processes'.")),
optparse.make_option("--experimental-fully-parallel",
action="store_true", default=False,
help="run all tests in parallel"),
@@ -415,10 +418,6 @@ def parse_args(args=None):
optparse.make_option("--test-results-server", default="",
help=("If specified, upload results json files to this appengine "
"server.")),
- optparse.make_option("--upload-full-results",
- action="store_true",
- default=False,
- help="If true, upload full json results to server."),
]
option_list = (configuration_options + print_options +
diff --git a/Tools/Scripts/webkitpy/layout_tests/run_webkit_tests_unittest.py b/Tools/Scripts/webkitpy/layout_tests/run_webkit_tests_unittest.py
index 677becd..84f5718 100644
--- a/Tools/Scripts/webkitpy/layout_tests/run_webkit_tests_unittest.py
+++ b/Tools/Scripts/webkitpy/layout_tests/run_webkit_tests_unittest.py
@@ -45,7 +45,7 @@ import unittest
from webkitpy.common import array_stream
from webkitpy.common.system import outputcapture
from webkitpy.common.system import filesystem_mock
-from webkitpy.common.system import user
+from webkitpy.tool import mocktool
from webkitpy.layout_tests import port
from webkitpy.layout_tests import run_webkit_tests
from webkitpy.layout_tests.layout_package import dump_render_tree_thread
@@ -56,14 +56,6 @@ from webkitpy.test.skip import skip_if
from webkitpy.thirdparty.mock import Mock
-class MockUser():
- def __init__(self):
- self.url = None
-
- def open_url(self, url):
- self.url = url
-
-
def parse_args(extra_args=None, record_results=False, tests_included=False,
print_nothing=True):
extra_args = extra_args or []
@@ -93,7 +85,7 @@ def passing_run(extra_args=None, port_obj=None, record_results=False,
tests_included)
if not port_obj:
port_obj = port.get(port_name=options.platform, options=options,
- user=MockUser(), filesystem=filesystem)
+ user=mocktool.MockUser(), filesystem=filesystem)
res = run_webkit_tests.run(port_obj, options, parsed_args)
return res == 0
@@ -103,7 +95,7 @@ def logging_run(extra_args=None, port_obj=None, record_results=False, tests_incl
record_results=record_results,
tests_included=tests_included,
print_nothing=False)
- user = MockUser()
+ user = mocktool.MockUser()
if not port_obj:
port_obj = port.get(port_name=options.platform, options=options,
user=user, filesystem=filesystem)
@@ -135,7 +127,7 @@ def get_tests_run(extra_args=None, tests_included=False, flatten_batches=False,
extra_args = ['passes', 'failures'] + extra_args
options, parsed_args = parse_args(extra_args, tests_included=True)
- user = MockUser()
+ user = mocktool.MockUser()
test_batches = []
@@ -216,7 +208,8 @@ class MainTest(unittest.TestCase):
def test_full_results_html(self):
# FIXME: verify html?
- self.assertTrue(passing_run(['--full-results-html']))
+ res, out, err, user = logging_run(['--full-results-html'])
+ self.assertEqual(res, 0)
def test_help_printing(self):
res, out, err, user = logging_run(['--help-printing'])
@@ -256,7 +249,7 @@ class MainTest(unittest.TestCase):
def test_lint_test_files__errors(self):
options, parsed_args = parse_args(['--lint-test-files'])
- user = MockUser()
+ user = mocktool.MockUser()
port_obj = port.get(options.platform, options=options, user=user)
port_obj.test_expectations = lambda: "# syntax error"
res, out, err = run_and_capture(port_obj, options, parsed_args)
@@ -352,7 +345,7 @@ class MainTest(unittest.TestCase):
self.assertEqual(res, 3)
self.assertFalse(out.empty())
self.assertFalse(err.empty())
- self.assertEqual(user.url, '/tmp/layout-test-results/results.html')
+ self.assertEqual(user.opened_urls, ['/tmp/layout-test-results/results.html'])
def test_exit_after_n_failures(self):
# Unexpected failures should result in tests stopping.
@@ -414,7 +407,7 @@ class MainTest(unittest.TestCase):
with fs.mkdtemp() as tmpdir:
res, out, err, user = logging_run(['--results-directory=' + str(tmpdir)],
tests_included=True, filesystem=fs)
- self.assertEqual(user.url, fs.join(tmpdir, 'results.html'))
+ self.assertEqual(user.opened_urls, [fs.join(tmpdir, 'results.html')])
def test_results_directory_default(self):
# We run a configuration that should fail, to generate output, then
@@ -422,7 +415,7 @@ class MainTest(unittest.TestCase):
# This is the default location.
res, out, err, user = logging_run(tests_included=True)
- self.assertEqual(user.url, '/tmp/layout-test-results/results.html')
+ self.assertEqual(user.opened_urls, ['/tmp/layout-test-results/results.html'])
def test_results_directory_relative(self):
# We run a configuration that should fail, to generate output, then
@@ -430,7 +423,7 @@ class MainTest(unittest.TestCase):
res, out, err, user = logging_run(['--results-directory=foo'],
tests_included=True)
- self.assertEqual(user.url, '/tmp/foo/results.html')
+ self.assertEqual(user.opened_urls, ['/tmp/foo/results.html'])
def test_tolerance(self):
class ImageDiffTestPort(TestPort):
@@ -441,7 +434,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())
+ test_port = ImageDiffTestPort(options=options, user=mocktool.MockUser())
passing_run(args, port_obj=test_port, tests_included=True)
return test_port
@@ -459,11 +452,27 @@ class MainTest(unittest.TestCase):
self.assertEqual(None, test_port.tolerance_used_for_diff_image)
def test_worker_model__inline(self):
+ self.assertTrue(passing_run(['--worker-model', 'inline']))
+
+ def test_worker_model__old_inline_with_child_processes(self):
+ res, out, err, user = logging_run(['--worker-model', 'old-inline',
+ '--child-processes', '2'])
+ self.assertEqual(res, 0)
+ self.assertTrue('--worker-model=old-inline overrides --child-processes\n' in err.get())
+
+ def test_worker_model__old_inline(self):
self.assertTrue(passing_run(['--worker-model', 'old-inline']))
- def test_worker_model__threads(self):
+ def test_worker_model__old_threads(self):
self.assertTrue(passing_run(['--worker-model', 'old-threads']))
+ def test_worker_model__processes(self):
+ if compare_version(sys, '2.6')[0] >= 0:
+ self.assertTrue(passing_run(['--worker-model', 'processes']))
+
+ def test_worker_model__threads(self):
+ self.assertTrue(passing_run(['--worker-model', 'threads']))
+
def test_worker_model__unknown(self):
self.assertRaises(ValueError, logging_run,
['--worker-model', 'unknown'])
@@ -491,7 +500,7 @@ class RebaselineTest(unittest.TestCase):
'failures/expected/missing_image.html'],
tests_included=True, filesystem=fs)
file_list = fs.written_files.keys()
- file_list.remove('/tmp/layout-test-results/tests_run.txt')
+ file_list.remove('/tmp/layout-test-results/tests_run0.txt')
self.assertEqual(len(file_list), 6)
self.assertBaselines(file_list,
"/passes/image")
@@ -508,12 +517,12 @@ class RebaselineTest(unittest.TestCase):
'failures/expected/missing_image.html'],
tests_included=True, filesystem=fs)
file_list = fs.written_files.keys()
- file_list.remove('/tmp/layout-test-results/tests_run.txt')
+ file_list.remove('/tmp/layout-test-results/tests_run0.txt')
self.assertEqual(len(file_list), 6)
self.assertBaselines(file_list,
- "/platform/test/passes/image")
+ "/platform/test-mac/passes/image")
self.assertBaselines(file_list,
- "/platform/test/failures/expected/missing_image")
+ "/platform/test-mac/failures/expected/missing_image")
class DryrunTest(unittest.TestCase):
diff --git a/Tools/Scripts/webkitpy/layout_tests/test_types/image_diff.py b/Tools/Scripts/webkitpy/layout_tests/test_types/image_diff.py
index 44605d2..1d7e107 100644
--- a/Tools/Scripts/webkitpy/layout_tests/test_types/image_diff.py
+++ b/Tools/Scripts/webkitpy/layout_tests/test_types/image_diff.py
@@ -49,23 +49,6 @@ _log = logging.getLogger("webkitpy.layout_tests.test_types.image_diff")
class ImageDiff(test_type_base.TestTypeBase):
- def _save_baseline_files(self, filename, image, image_hash,
- generate_new_baseline):
- """Saves new baselines for the PNG and checksum.
-
- Args:
- filename: test filename
- image: a image output
- image_hash: a checksum of the image
- generate_new_baseline: whether to generate a new, platform-specific
- baseline, or update the existing one
- """
- self._save_baseline_data(filename, image, ".png", encoding=None,
- generate_new_baseline=generate_new_baseline)
- self._save_baseline_data(filename, image_hash, ".checksum",
- encoding="ascii",
- generate_new_baseline=generate_new_baseline)
-
def _copy_image(self, filename, actual_image, expected_image):
self.write_output_files(filename, '.png',
output=actual_image, expected=expected_image,
@@ -85,54 +68,47 @@ class ImageDiff(test_type_base.TestTypeBase):
self.FILENAME_SUFFIX_COMPARE)
return port.diff_image(actual_image, expected_image, diff_filename)
- def compare_output(self, port, filename, test_args, actual_test_output,
- expected_test_output):
+ def compare_output(self, port, filename, options, actual_driver_output,
+ expected_driver_output):
"""Implementation of CompareOutput that checks the output image and
checksum against the expected files from the LayoutTest directory.
"""
failures = []
# If we didn't produce a hash file, this test must be text-only.
- if actual_test_output.image_hash is None:
- return failures
-
- # If we're generating a new baseline, we pass.
- if test_args.new_baseline or test_args.reset_results:
- self._save_baseline_files(filename, actual_test_output.image,
- actual_test_output.image_hash,
- test_args.new_baseline)
+ if actual_driver_output.image_hash is None:
return failures
- if not expected_test_output.image:
+ if not expected_driver_output.image:
# Report a missing expected PNG file.
- self._copy_image(filename, actual_test_output.image, expected_image=None)
- self._copy_image_hash(filename, actual_test_output.image_hash,
- expected_test_output.image_hash)
+ self._copy_image(filename, actual_driver_output.image, expected_image=None)
+ self._copy_image_hash(filename, actual_driver_output.image_hash,
+ expected_driver_output.image_hash)
failures.append(test_failures.FailureMissingImage())
return failures
- if not expected_test_output.image_hash:
+ if not expected_driver_output.image_hash:
# Report a missing expected checksum file.
- self._copy_image(filename, actual_test_output.image,
- expected_test_output.image)
- self._copy_image_hash(filename, actual_test_output.image_hash,
+ self._copy_image(filename, actual_driver_output.image,
+ expected_driver_output.image)
+ self._copy_image_hash(filename, actual_driver_output.image_hash,
expected_image_hash=None)
failures.append(test_failures.FailureMissingImageHash())
return failures
- if actual_test_output.image_hash == expected_test_output.image_hash:
+ if actual_driver_output.image_hash == expected_driver_output.image_hash:
# Hash matched (no diff needed, okay to return).
return failures
- self._copy_image(filename, actual_test_output.image,
- expected_test_output.image)
- self._copy_image_hash(filename, actual_test_output.image_hash,
- expected_test_output.image_hash)
+ self._copy_image(filename, actual_driver_output.image,
+ expected_driver_output.image)
+ self._copy_image_hash(filename, actual_driver_output.image_hash,
+ expected_driver_output.image_hash)
# Even though we only use the result in one codepath below but we
# still need to call CreateImageDiff for other codepaths.
images_are_different = self._create_diff_image(port, filename,
- actual_test_output.image,
- expected_test_output.image)
+ actual_driver_output.image,
+ expected_driver_output.image)
if not images_are_different:
failures.append(test_failures.FailureImageHashIncorrect())
else:
diff --git a/Tools/Scripts/webkitpy/layout_tests/test_types/test_type_base.py b/Tools/Scripts/webkitpy/layout_tests/test_types/test_type_base.py
index ad65016..09bfc31 100644
--- a/Tools/Scripts/webkitpy/layout_tests/test_types/test_type_base.py
+++ b/Tools/Scripts/webkitpy/layout_tests/test_types/test_type_base.py
@@ -28,8 +28,6 @@
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
"""Defines the interface TestTypeBase which other test types inherit from.
-
-Also defines the TestArguments "struct" to pass them additional arguments.
"""
import cgi
@@ -39,21 +37,6 @@ import logging
_log = logging.getLogger("webkitpy.layout_tests.test_types.test_type_base")
-class TestArguments(object):
- """Struct-like wrapper for additional arguments needed by
- specific tests."""
- # Whether to save new baseline results.
- new_baseline = False
-
- # Path to the actual PNG file generated by pixel tests
- png_path = None
-
- # Value of checksum generated by pixel tests.
- hash = None
-
- # Whether to use wdiff to generate by-word diffs.
- wdiff = False
-
# Python bug workaround. See the wdiff code in WriteOutputFiles for an
# explanation.
_wdiff_available = True
@@ -87,39 +70,6 @@ class TestTypeBase(object):
self._port.relative_test_filename(filename))
fs.maybe_make_directory(fs.dirname(output_filename))
- def _save_baseline_data(self, filename, data, modifier, encoding,
- generate_new_baseline=True):
- """Saves a new baseline file into the port's baseline directory.
-
- The file will be named simply "<test>-expected<modifier>", suitable for
- use as the expected results in a later run.
-
- Args:
- filename: path to the test file
- data: result to be saved as the new baseline
- modifier: type of the result file, e.g. ".txt" or ".png"
- encoding: file encoding (none, "utf-8", etc.)
- generate_new_baseline: whether to enerate a new, platform-specific
- baseline, or update the existing one
- """
-
- port = self._port
- fs = self._port._filesystem
- if generate_new_baseline:
- relative_dir = fs.dirname(port.relative_test_filename(filename))
- baseline_path = port.baseline_path()
- output_dir = fs.join(baseline_path, relative_dir)
- output_file = fs.basename(fs.splitext(filename)[0] +
- self.FILENAME_SUFFIX_EXPECTED + modifier)
- fs.maybe_make_directory(output_dir)
- output_path = fs.join(output_dir, output_file)
- _log.debug('writing new baseline result "%s"' % (output_path))
- else:
- output_path = port.expected_filename(filename, modifier)
- _log.debug('resetting baseline result "%s"' % output_path)
-
- port.update_baseline(output_path, data, encoding)
-
def output_filename(self, filename, modifier):
"""Returns a filename inside the output dir that contains modifier.
@@ -139,8 +89,8 @@ class TestTypeBase(object):
self._port.relative_test_filename(filename))
return fs.splitext(output_filename)[0] + modifier
- def compare_output(self, port, filename, test_args, actual_test_output,
- expected_test_output):
+ def compare_output(self, port, filename, options, actual_driver_output,
+ expected_driver_output):
"""Method that compares the output from the test with the
expected value.
@@ -149,12 +99,11 @@ class TestTypeBase(object):
Args:
port: object implementing port-specific information and methods
filename: absolute filename to test file
- test_args: a TestArguments object holding optional additional
- arguments
- actual_test_output: a TestOutput object which represents actual test
+ options: command line argument object from optparse
+ actual_driver_output: a DriverOutput object which represents actual test
output
- expected_test_output: a TestOutput object which represents a expected
- test output
+ expected_driver_output: a ExpectedDriverOutput object which represents a
+ expected test output
Return:
a list of TestFailure objects, empty if the test passes
diff --git a/Tools/Scripts/webkitpy/layout_tests/test_types/test_type_base_unittest.py b/Tools/Scripts/webkitpy/layout_tests/test_types/test_type_base_unittest.py
index 5dbfcb6..7af4d9c 100644
--- a/Tools/Scripts/webkitpy/layout_tests/test_types/test_type_base_unittest.py
+++ b/Tools/Scripts/webkitpy/layout_tests/test_types/test_type_base_unittest.py
@@ -40,7 +40,7 @@ class Test(unittest.TestCase):
test_type = test_type_base.TestTypeBase(None, None)
self.assertRaises(NotImplementedError, test_type.compare_output,
None, "foo.txt", '',
- test_type_base.TestArguments(), 'Debug')
+ {}, 'Debug')
if __name__ == '__main__':
diff --git a/Tools/Scripts/webkitpy/layout_tests/test_types/text_diff.py b/Tools/Scripts/webkitpy/layout_tests/test_types/text_diff.py
index 7b7febe..07c3d03 100644
--- a/Tools/Scripts/webkitpy/layout_tests/test_types/text_diff.py
+++ b/Tools/Scripts/webkitpy/layout_tests/test_types/text_diff.py
@@ -53,26 +53,16 @@ class TestTextDiff(test_type_base.TestTypeBase):
# the normalized text expectation files.
return output.replace("\r\r\n", "\r\n").replace("\r\n", "\n")
- def compare_output(self, port, filename, test_args, actual_test_output,
- expected_test_output):
+ def compare_output(self, port, filename, options, actual_driver_output,
+ expected_driver_output):
"""Implementation of CompareOutput that checks the output text against
the expected text from the LayoutTest directory."""
failures = []
- # If we're generating a new baseline, we pass.
- if test_args.new_baseline or test_args.reset_results:
- # Although all test_shell/DumpRenderTree output should be utf-8,
- # we do not ever decode it inside run-webkit-tests. For some tests
- # DumpRenderTree may not output utf-8 text (e.g. webarchives).
- self._save_baseline_data(filename, actual_test_output.text,
- ".txt", encoding=None,
- generate_new_baseline=test_args.new_baseline)
- return failures
-
# Normalize text to diff
- actual_text = self._get_normalized_output_text(actual_test_output.text)
+ actual_text = self._get_normalized_output_text(actual_driver_output.text)
# Assuming expected_text is already normalized.
- expected_text = expected_test_output.text
+ expected_text = expected_driver_output.text
# Write output files for new tests, too.
if port.compare_text(actual_text, expected_text):
diff --git a/Tools/Scripts/webkitpy/layout_tests/update_webgl_conformance_tests.py b/Tools/Scripts/webkitpy/layout_tests/update_webgl_conformance_tests.py
index f4c8098..7267aa6 100755
--- a/Tools/Scripts/webkitpy/layout_tests/update_webgl_conformance_tests.py
+++ b/Tools/Scripts/webkitpy/layout_tests/update_webgl_conformance_tests.py
@@ -31,7 +31,7 @@ import optparse
import os
import re
import sys
-import webkitpy.common.checkout.scm as scm
+from webkitpy.common.checkout import scm
_log = logging.getLogger("webkitpy.layout_tests."
"update-webgl-conformance-tests")
diff --git a/Tools/Scripts/webkitpy/style/checker.py b/Tools/Scripts/webkitpy/style/checker.py
index ebcf326..23b9ab3 100644
--- a/Tools/Scripts/webkitpy/style/checker.py
+++ b/Tools/Scripts/webkitpy/style/checker.py
@@ -129,17 +129,20 @@ _PATH_RULES_SPECIFIER = [
([# The EFL APIs use EFL naming style, which includes
# both lower-cased and camel-cased, underscore-sparated
# values.
- "WebKit/efl/ewk/",
+ "Source/WebKit/efl/ewk/",
# There is no clean way to avoid "yy_*" names used by flex.
"Source/WebCore/css/CSSParser.cpp",
# Qt code uses '_' in some places (such as private slots
# and on test xxx_data methos on tests)
"Source/JavaScriptCore/qt/",
- "WebKit/qt/Api/",
- "WebKit/qt/tests/",
- "WebKit/qt/declarative/",
- "WebKit/qt/examples/"],
+ "Source/WebKit/qt/Api/",
+ "Source/WebKit/qt/tests/",
+ "Source/WebKit/qt/declarative/",
+ "Source/WebKit/qt/examples/"],
["-readability/naming"]),
+ ([# Qt's MiniBrowser has no config.h
+ "Tools/MiniBrowser/qt"],
+ ["-build/include"]),
([# The GTK+ APIs use GTK+ naming style, which includes
# lower-cased, underscore-separated values.
# Also, GTK+ allows the use of NULL.
@@ -162,24 +165,18 @@ _PATH_RULES_SPECIFIER = [
"-whitespace/parens"]),
# WebKit2 rules:
- # WebKit2 doesn't use config.h, and certain directories have other
- # idiosyncracies.
+ # WebKit2 and certain directories have idiosyncracies.
([# NPAPI has function names with underscores.
"Source/WebKit2/WebProcess/Plugins/Netscape"],
- ["-build/include_order",
- "-readability/naming"]),
+ ["-readability/naming"]),
([# The WebKit2 C API has names with underscores and whitespace-aligned
# struct members. Also, we allow unnecessary parameter names in
# WebKit2 APIs because we're matching CF's header style.
"Source/WebKit2/UIProcess/API/C/",
"Source/WebKit2/WebProcess/InjectedBundle/API/c/"],
- ["-build/include_order",
- "-readability/naming",
+ ["-readability/naming",
"-readability/parameter_name",
"-whitespace/declaration"]),
- ([# Nothing in WebKit2 uses config.h.
- "Source/WebKit2/"],
- ["-build/include_order"]),
# For third-party Python code, keep only the following checks--
#
@@ -243,7 +240,7 @@ _XML_FILE_EXTENSIONS = [
_SKIPPED_FILES_WITH_WARNING = [
"gtk2drawing.c", # WebCore/platform/gtk/gtk2drawing.c
"gtkdrawing.h", # WebCore/platform/gtk/gtkdrawing.h
- "WebKit/gtk/tests/",
+ "Source/WebKit/gtk/tests/",
# Soup API that is still being cooked, will be removed from WebKit
# in a few months when it is merged into soup proper. The style
# follows the libsoup style completely.
diff --git a/Tools/Scripts/webkitpy/style/checker_unittest.py b/Tools/Scripts/webkitpy/style/checker_unittest.py
index a4649d2..a796e0b 100755
--- a/Tools/Scripts/webkitpy/style/checker_unittest.py
+++ b/Tools/Scripts/webkitpy/style/checker_unittest.py
@@ -216,11 +216,11 @@ class GlobalVariablesTest(unittest.TestCase):
"build/include")
assertCheck("random_path.cpp",
"readability/naming")
- assertNoCheck("WebKit/gtk/webkit/webkit.h",
+ assertNoCheck("Source/WebKit/gtk/webkit/webkit.h",
"readability/naming")
assertNoCheck("Tools/DumpRenderTree/gtk/DumpRenderTree.cpp",
"readability/null")
- assertNoCheck("WebKit/efl/ewk/ewk_view.h",
+ assertNoCheck("Source/WebKit/efl/ewk/ewk_view.h",
"readability/naming")
assertNoCheck("Source/WebCore/css/CSSParser.cpp",
"readability/naming")
@@ -228,28 +228,31 @@ class GlobalVariablesTest(unittest.TestCase):
# Test if Qt exceptions are indeed working
assertCheck("Source/JavaScriptCore/qt/api/qscriptengine.cpp",
"readability/braces")
- assertCheck("WebKit/qt/Api/qwebpage.cpp",
+ assertCheck("Source/WebKit/qt/Api/qwebpage.cpp",
"readability/braces")
- assertCheck("WebKit/qt/tests/qwebelement/tst_qwebelement.cpp",
+ assertCheck("Source/WebKit/qt/tests/qwebelement/tst_qwebelement.cpp",
"readability/braces")
- assertCheck("WebKit/qt/declarative/platformplugin/WebPlugin.cpp",
+ assertCheck("Source/WebKit/qt/declarative/platformplugin/WebPlugin.cpp",
"readability/braces")
- assertCheck("WebKit/qt/examples/platformplugin/WebPlugin.cpp",
+ assertCheck("Source/WebKit/qt/examples/platformplugin/WebPlugin.cpp",
"readability/braces")
assertNoCheck("Source/JavaScriptCore/qt/api/qscriptengine.cpp",
"readability/naming")
assertNoCheck("Source/JavaScriptCore/qt/benchmarks"
"/qscriptengine/tst_qscriptengine.cpp",
"readability/naming")
- assertNoCheck("WebKit/qt/Api/qwebpage.cpp",
+ assertNoCheck("Source/WebKit/qt/Api/qwebpage.cpp",
"readability/naming")
- assertNoCheck("WebKit/qt/tests/qwebelement/tst_qwebelement.cpp",
+ assertNoCheck("Source/WebKit/qt/tests/qwebelement/tst_qwebelement.cpp",
"readability/naming")
- assertNoCheck("WebKit/qt/declarative/platformplugin/WebPlugin.cpp",
+ assertNoCheck("Source/WebKit/qt/declarative/platformplugin/WebPlugin.cpp",
"readability/naming")
- assertNoCheck("WebKit/qt/examples/platformplugin/WebPlugin.cpp",
+ assertNoCheck("Source/WebKit/qt/examples/platformplugin/WebPlugin.cpp",
"readability/naming")
+ assertNoCheck("Tools/MiniBrowser/qt/UrlLoader.cpp",
+ "build/include")
+
assertNoCheck("Source/WebCore/ForwardingHeaders/debugger/Debugger.h",
"build/header_guard")
@@ -301,7 +304,7 @@ class CheckerDispatcherSkipTest(unittest.TestCase):
"gtkdrawing.h",
"Source/WebCore/platform/gtk/gtk2drawing.c",
"Source/WebCore/platform/gtk/gtkdrawing.h",
- "WebKit/gtk/tests/testatk.c",
+ "Source/WebKit/gtk/tests/testatk.c",
]
for path in paths_to_skip:
diff --git a/Tools/Scripts/webkitpy/style/checkers/cpp.py b/Tools/Scripts/webkitpy/style/checkers/cpp.py
index 250b9ee..671fd56 100644
--- a/Tools/Scripts/webkitpy/style/checkers/cpp.py
+++ b/Tools/Scripts/webkitpy/style/checkers/cpp.py
@@ -194,6 +194,31 @@ def iteratively_replace_matches_with_char(pattern, char_replacement, s):
s = s[:start_match_index] + char_replacement * match_length + s[end_match_index:]
+def _rfind_in_lines(regex, lines, start_position, not_found_position):
+ """Does a reverse find starting at start position and going backwards until
+ a match is found.
+
+ Returns the position where the regex ended.
+ """
+ # Put the regex in a group and proceed it with a greedy expression that
+ # matches anything to ensure that we get the last possible match in a line.
+ last_in_line_regex = r'.*(' + regex + ')'
+ current_row = start_position.row
+
+ # Start with the given row and trim off everything past what may be matched.
+ current_line = lines[start_position.row][:start_position.column]
+ while True:
+ found_match = match(last_in_line_regex, current_line)
+ if found_match:
+ return Position(current_row, found_match.end(1))
+
+ # A match was not found so continue backward.
+ current_row -= 1
+ if current_row < 0:
+ return not_found_position
+ current_line = lines[current_row]
+
+
def _convert_to_lower_with_underscores(text):
"""Converts all text strings in camelCase or PascalCase to lowers with underscores."""
@@ -526,6 +551,15 @@ class _FunctionState(object):
self._clean_lines = clean_lines
self._parameter_list = None
+ def modifiers_and_return_type(self):
+ """Returns the modifiers and the return type."""
+ # Go backwards from where the function name is until we encounter one of several things:
+ # ';' or '{' or '}' or 'private:', etc. or '#' or return Position(0, 0)
+ elided = self._clean_lines.elided
+ start_modifiers = _rfind_in_lines(r';|\{|\}|((private|public|protected):)|(#.*)',
+ elided, self.parameter_start_position, Position(0, 0))
+ return SingleLineView(elided, start_modifiers, self.function_name_start_position).single_line.strip()
+
def parameter_list(self):
if not self._parameter_list:
# Store the final result as a tuple since that is immutable.
@@ -2315,7 +2349,7 @@ def check_for_null(clean_lines, line_number, file_state, error):
# matches, then do the check with strings collapsed to avoid giving errors for
# NULLs occurring in strings.
if search(r'\bNULL\b', line) and search(r'\bNULL\b', CleansedLines.collapse_strings(line)):
- error(line_number, 'readability/null', 4, 'Use 0 instead of NULL.')
+ error(line_number, 'readability/null', 4, 'Use 0 or null instead of NULL (even in *comments*).')
def get_line_width(line):
"""Determines the width of the line in column positions.
diff --git a/Tools/Scripts/webkitpy/style/checkers/cpp_unittest.py b/Tools/Scripts/webkitpy/style/checkers/cpp_unittest.py
index 868d3f6..53670d7 100644
--- a/Tools/Scripts/webkitpy/style/checkers/cpp_unittest.py
+++ b/Tools/Scripts/webkitpy/style/checkers/cpp_unittest.py
@@ -352,16 +352,17 @@ class CppStyleTestBase(unittest.TestCase):
class FunctionDetectionTest(CppStyleTestBase):
- def perform_function_detection(self, lines, function_information):
+ def perform_function_detection(self, lines, function_information, detection_line=0):
clean_lines = cpp_style.CleansedLines(lines)
function_state = cpp_style._FunctionState(5)
error_collector = ErrorCollector(self.assert_)
- cpp_style.detect_functions(clean_lines, 0, function_state, error_collector)
+ cpp_style.detect_functions(clean_lines, detection_line, function_state, error_collector)
if not function_information:
self.assertEquals(function_state.in_a_function, False)
return
self.assertEquals(function_state.in_a_function, True)
self.assertEquals(function_state.current_function, function_information['name'] + '()')
+ self.assertEquals(function_state.modifiers_and_return_type(), function_information['modifiers_and_return_type'])
self.assertEquals(function_state.is_pure, function_information['is_pure'])
self.assertEquals(function_state.is_declaration, function_information['is_declaration'])
self.assert_positions_equal(function_state.function_name_start_position, function_information['function_name_start_position'])
@@ -385,6 +386,7 @@ class FunctionDetectionTest(CppStyleTestBase):
['void theTestFunctionName(int) {',
'}'],
{'name': 'theTestFunctionName',
+ 'modifiers_and_return_type': 'void',
'function_name_start_position': (0, 5),
'parameter_start_position': (0, 24),
'parameter_end_position': (0, 29),
@@ -397,6 +399,7 @@ class FunctionDetectionTest(CppStyleTestBase):
self.perform_function_detection(
['void aFunctionName(int);'],
{'name': 'aFunctionName',
+ 'modifiers_and_return_type': 'void',
'function_name_start_position': (0, 5),
'parameter_start_position': (0, 18),
'parameter_end_position': (0, 23),
@@ -408,6 +411,7 @@ class FunctionDetectionTest(CppStyleTestBase):
self.perform_function_detection(
['CheckedInt<T> operator /(const CheckedInt<T> &lhs, const CheckedInt<T> &rhs);'],
{'name': 'operator /',
+ 'modifiers_and_return_type': 'CheckedInt<T>',
'function_name_start_position': (0, 14),
'parameter_start_position': (0, 24),
'parameter_end_position': (0, 76),
@@ -419,6 +423,7 @@ class FunctionDetectionTest(CppStyleTestBase):
self.perform_function_detection(
['CheckedInt<T> operator -(const CheckedInt<T> &lhs, const CheckedInt<T> &rhs);'],
{'name': 'operator -',
+ 'modifiers_and_return_type': 'CheckedInt<T>',
'function_name_start_position': (0, 14),
'parameter_start_position': (0, 24),
'parameter_end_position': (0, 76),
@@ -430,6 +435,7 @@ class FunctionDetectionTest(CppStyleTestBase):
self.perform_function_detection(
['CheckedInt<T> operator !=(const CheckedInt<T> &lhs, const CheckedInt<T> &rhs);'],
{'name': 'operator !=',
+ 'modifiers_and_return_type': 'CheckedInt<T>',
'function_name_start_position': (0, 14),
'parameter_start_position': (0, 25),
'parameter_end_position': (0, 77),
@@ -441,6 +447,7 @@ class FunctionDetectionTest(CppStyleTestBase):
self.perform_function_detection(
['CheckedInt<T> operator +(const CheckedInt<T> &lhs, const CheckedInt<T> &rhs);'],
{'name': 'operator +',
+ 'modifiers_and_return_type': 'CheckedInt<T>',
'function_name_start_position': (0, 14),
'parameter_start_position': (0, 24),
'parameter_end_position': (0, 76),
@@ -453,6 +460,7 @@ class FunctionDetectionTest(CppStyleTestBase):
self.perform_function_detection(
['virtual void theTestFunctionName(int = 0);'],
{'name': 'theTestFunctionName',
+ 'modifiers_and_return_type': 'virtual void',
'function_name_start_position': (0, 13),
'parameter_start_position': (0, 32),
'parameter_end_position': (0, 41),
@@ -464,6 +472,7 @@ class FunctionDetectionTest(CppStyleTestBase):
self.perform_function_detection(
['virtual void theTestFunctionName(int) = 0;'],
{'name': 'theTestFunctionName',
+ 'modifiers_and_return_type': 'virtual void',
'function_name_start_position': (0, 13),
'parameter_start_position': (0, 32),
'parameter_end_position': (0, 37),
@@ -478,6 +487,7 @@ class FunctionDetectionTest(CppStyleTestBase):
' = ',
' 0 ;'],
{'name': 'theTestFunctionName',
+ 'modifiers_and_return_type': 'virtual void',
'function_name_start_position': (0, 13),
'parameter_start_position': (0, 32),
'parameter_end_position': (0, 37),
@@ -498,6 +508,7 @@ class FunctionDetectionTest(CppStyleTestBase):
# This isn't a function but it looks like one to our simple
# algorithm and that is ok.
{'name': 'asm',
+ 'modifiers_and_return_type': '',
'function_name_start_position': (0, 0),
'parameter_start_position': (0, 3),
'parameter_end_position': (2, 1),
@@ -514,6 +525,7 @@ class FunctionDetectionTest(CppStyleTestBase):
function_state = self.perform_function_detection(
['void functionName();'],
{'name': 'functionName',
+ 'modifiers_and_return_type': 'void',
'function_name_start_position': (0, 5),
'parameter_start_position': (0, 17),
'parameter_end_position': (0, 19),
@@ -527,6 +539,7 @@ class FunctionDetectionTest(CppStyleTestBase):
function_state = self.perform_function_detection(
['void functionName(int);'],
{'name': 'functionName',
+ 'modifiers_and_return_type': 'void',
'function_name_start_position': (0, 5),
'parameter_start_position': (0, 17),
'parameter_end_position': (0, 22),
@@ -541,6 +554,7 @@ class FunctionDetectionTest(CppStyleTestBase):
function_state = self.perform_function_detection(
['void functionName(unsigned a, short b, long c, long long short unsigned int);'],
{'name': 'functionName',
+ 'modifiers_and_return_type': 'void',
'function_name_start_position': (0, 5),
'parameter_start_position': (0, 17),
'parameter_end_position': (0, 76),
@@ -558,6 +572,7 @@ class FunctionDetectionTest(CppStyleTestBase):
function_state = self.perform_function_detection(
['virtual void determineARIADropEffects(Vector<String>*&, const unsigned long int*&, const MediaPlayer::Preload, Other<Other2, Other3<P1, P2> >, int);'],
{'name': 'determineARIADropEffects',
+ 'modifiers_and_return_type': 'virtual void',
'parameter_start_position': (0, 37),
'function_name_start_position': (0, 13),
'parameter_end_position': (0, 147),
@@ -574,23 +589,27 @@ class FunctionDetectionTest(CppStyleTestBase):
# Try parsing a function with a very complex definition.
function_state = self.perform_function_detection(
- ['AnotherTemplate<Class1, Class2> aFunctionName(PassRefPtr<MyClass> paramName,',
+ ['#define MyMacro(a) a',
+ 'virtual',
+ 'AnotherTemplate<Class1, Class2> aFunctionName(PassRefPtr<MyClass> paramName,',
'const Other1Class& foo,',
'const ComplexTemplate<Class1, NestedTemplate<P1, P2> >* const * param = new ComplexTemplate<Class1, NestedTemplate<P1, P2> >(34, 42),',
'int* myCount = 0);'],
{'name': 'aFunctionName',
- 'function_name_start_position': (0, 32),
- 'parameter_start_position': (0, 45),
- 'parameter_end_position': (3, 17),
- 'body_start_position': (3, 17),
- 'end_position': (3, 18),
+ 'modifiers_and_return_type': 'virtual AnotherTemplate<Class1, Class2>',
+ 'function_name_start_position': (2, 32),
+ 'parameter_start_position': (2, 45),
+ 'parameter_end_position': (5, 17),
+ 'body_start_position': (5, 17),
+ 'end_position': (5, 18),
'is_pure': False,
'is_declaration': True,
'parameter_list':
- ({'type': 'PassRefPtr<MyClass>', 'name': 'paramName', 'row': 0},
- {'type': 'const Other1Class&', 'name': 'foo', 'row': 1},
- {'type': 'const ComplexTemplate<Class1, NestedTemplate<P1, P2> >* const *', 'name': 'param', 'row': 2},
- {'type': 'int*', 'name': 'myCount', 'row': 3})})
+ ({'type': 'PassRefPtr<MyClass>', 'name': 'paramName', 'row': 2},
+ {'type': 'const Other1Class&', 'name': 'foo', 'row': 3},
+ {'type': 'const ComplexTemplate<Class1, NestedTemplate<P1, P2> >* const *', 'name': 'param', 'row': 4},
+ {'type': 'int*', 'name': 'myCount', 'row': 5})},
+ detection_line=2)
class CppStyleTest(CppStyleTestBase):
@@ -630,6 +649,14 @@ class CppStyleTest(CppStyleTestBase):
self.assertTrue(position < cpp_style.Position(position.row + 1, position.column - 1))
self.assertEquals(position.__str__(), '(3, 4)')
+ def test_rfind_in_lines(self):
+ not_found_position = cpp_style.Position(10, 11)
+ start_position = cpp_style.Position(2, 2)
+ lines = ['ab', 'ace', 'test']
+ self.assertEquals(not_found_position, cpp_style._rfind_in_lines('st', lines, start_position, not_found_position))
+ self.assertTrue(cpp_style.Position(1, 1) == cpp_style._rfind_in_lines('a', lines, start_position, not_found_position))
+ self.assertEquals(cpp_style.Position(2, 2), cpp_style._rfind_in_lines('(te|a)', lines, start_position, not_found_position))
+
def test_close_expression(self):
self.assertEquals(cpp_style.Position(1, -1), cpp_style.close_expression([')('], cpp_style.Position(0, 1)))
self.assertEquals(cpp_style.Position(1, -1), cpp_style.close_expression([') ()'], cpp_style.Position(0, 1)))
@@ -3901,12 +3928,12 @@ class WebKitStyleTest(CppStyleTestBase):
'foo.cpp')
self.assert_lint(
"// Don't use NULL in comments since it isn't in code.",
- 'Use 0 instead of NULL.'
+ 'Use 0 or null instead of NULL (even in *comments*).'
' [readability/null] [4]',
'foo.cpp')
self.assert_lint(
'"A string with NULL" // and a comment with NULL is tricky to flag correctly in cpp_style.',
- 'Use 0 instead of NULL.'
+ 'Use 0 or null instead of NULL (even in *comments*).'
' [readability/null] [4]',
'foo.cpp')
self.assert_lint(
diff --git a/Tools/Scripts/webkitpy/style/checkers/test_expectations.py b/Tools/Scripts/webkitpy/style/checkers/test_expectations.py
index c86b32c..e37f908 100644
--- a/Tools/Scripts/webkitpy/style/checkers/test_expectations.py
+++ b/Tools/Scripts/webkitpy/style/checkers/test_expectations.py
@@ -75,7 +75,6 @@ class TestExpectationsChecker(object):
"Using 'test' port, but platform-specific expectations "
"will fail the check." % self._file_path)
self._port_obj = port.get('test')
- self._port_to_check = self._port_obj.test_platform_name()
# Suppress error messages of test_expectations module since they will be
# reported later.
log = logging.getLogger("webkitpy.layout_tests.layout_package."
@@ -91,7 +90,7 @@ class TestExpectationsChecker(object):
try:
expectations = test_expectations.TestExpectationsFile(
port=self._port_obj, expectations=expectations_str, full_test_list=tests,
- test_platform_name=self._port_to_check, is_debug_mode=False,
+ test_config=self._port_obj.test_configuration(),
is_lint_mode=True, overrides=overrides)
except test_expectations.ParseError, error:
err = error
diff --git a/Tools/Scripts/webkitpy/style/checkers/test_expectations_unittest.py b/Tools/Scripts/webkitpy/style/checkers/test_expectations_unittest.py
index 9817c5d..f0813e1 100644
--- a/Tools/Scripts/webkitpy/style/checkers/test_expectations_unittest.py
+++ b/Tools/Scripts/webkitpy/style/checkers/test_expectations_unittest.py
@@ -84,15 +84,6 @@ class TestExpectationsTestCase(unittest.TestCase):
def test_valid_expectations(self):
self.assert_lines_lint(
- ["passes/text.html = PASS"],
- "")
- self.assert_lines_lint(
- ["passes/text.html = FAIL PASS"],
- "")
- self.assert_lines_lint(
- ["passes/text.html = CRASH TIMEOUT FAIL PASS"],
- "")
- self.assert_lines_lint(
["BUGCR1234 MAC : passes/text.html = PASS FAIL"],
"")
self.assert_lines_lint(
@@ -120,12 +111,12 @@ class TestExpectationsTestCase(unittest.TestCase):
def test_modifier_errors(self):
self.assert_lines_lint(
["BUG1234 : passes/text.html = FAIL"],
- 'Bug must be either BUGCR, BUGWK, or BUGV8_ for test: bug1234 passes/text.html [test/expectations] [5]')
+ "BUG\\d+ is not allowed, must be one of BUGCR\\d+, BUGWK\\d+, BUGV8_\\d+, or a non-numeric bug identifier. passes/text.html [test/expectations] [5]")
def test_valid_modifiers(self):
self.assert_lines_lint(
["INVALID-MODIFIER : passes/text.html = PASS"],
- "Invalid modifier for test: invalid-modifier "
+ "Unrecognized option 'invalid-modifier' "
"passes/text.html [test/expectations] [5]")
self.assert_lines_lint(
["SKIP : passes/text.html = PASS"],
@@ -135,38 +126,38 @@ class TestExpectationsTestCase(unittest.TestCase):
def test_expectation_errors(self):
self.assert_lines_lint(
["missing expectations"],
- "Missing expectations. ['missing expectations'] [test/expectations] [5]")
+ "Missing a ':' missing expectations [test/expectations] [5]")
self.assert_lines_lint(
["SLOW : passes/text.html = TIMEOUT"],
- "A test can not be both slow and timeout. "
- "If it times out indefinitely, then it should be just timeout. "
+ "A test can not be both SLOW and TIMEOUT. "
+ "If it times out indefinitely, then it should be just TIMEOUT. "
"passes/text.html [test/expectations] [5]")
self.assert_lines_lint(
- ["does/not/exist.html = FAIL"],
+ ["BUGWK1 : does/not/exist.html = FAIL"],
"Path does not exist. does/not/exist.html [test/expectations] [2]")
def test_parse_expectations(self):
self.assert_lines_lint(
- ["passes/text.html = PASS"],
+ ["BUGWK1 : passes/text.html = PASS"],
"")
self.assert_lines_lint(
- ["passes/text.html = UNSUPPORTED"],
+ ["BUGWK1 : passes/text.html = UNSUPPORTED"],
"Unsupported expectation: unsupported "
"passes/text.html [test/expectations] [5]")
self.assert_lines_lint(
- ["passes/text.html = PASS UNSUPPORTED"],
+ ["BUGWK1 : passes/text.html = PASS UNSUPPORTED"],
"Unsupported expectation: unsupported "
"passes/text.html [test/expectations] [5]")
def test_already_seen_test(self):
self.assert_lines_lint(
- ["passes/text.html = PASS",
- "passes/text.html = TIMEOUT"],
- "Duplicate expectation. %s [test/expectations] [5]" % self._test_file)
+ ["BUGWK1 : passes/text.html = PASS",
+ "BUGWK1 : passes/text.html = TIMEOUT"],
+ "Duplicate or ambiguous expectation. %s [test/expectations] [5]" % self._test_file)
def test_tab(self):
self.assert_lines_lint(
- ["\tpasses/text.html = PASS"],
+ ["\tBUGWK1 : passes/text.html = PASS"],
"Line contains tab character. [whitespace/tab] [5]")
if __name__ == '__main__':
diff --git a/Tools/Scripts/webkitpy/tool/bot/irc_command.py b/Tools/Scripts/webkitpy/tool/bot/irc_command.py
index 265974e..67a1c44 100644
--- a/Tools/Scripts/webkitpy/tool/bot/irc_command.py
+++ b/Tools/Scripts/webkitpy/tool/bot/irc_command.py
@@ -27,7 +27,7 @@
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
import random
-import webkitpy.common.config.irc as config_irc
+from webkitpy.common.config import irc as config_irc
from webkitpy.common.config import urls
from webkitpy.common.net.bugzilla import parse_bug_id
diff --git a/Tools/Scripts/webkitpy/tool/bot/sheriffircbot.py b/Tools/Scripts/webkitpy/tool/bot/sheriffircbot.py
index de77222..29e89a8 100644
--- a/Tools/Scripts/webkitpy/tool/bot/sheriffircbot.py
+++ b/Tools/Scripts/webkitpy/tool/bot/sheriffircbot.py
@@ -26,7 +26,7 @@
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-import webkitpy.tool.bot.irc_command as irc_command
+from webkitpy.tool.bot import irc_command
from webkitpy.common.net.irc.ircbot import IRCBotDelegate
from webkitpy.common.thread.threadedmessagequeue import ThreadedMessageQueue
diff --git a/Tools/Scripts/webkitpy/tool/commands/__init__.py b/Tools/Scripts/webkitpy/tool/commands/__init__.py
index a974b67..26bd195 100644
--- a/Tools/Scripts/webkitpy/tool/commands/__init__.py
+++ b/Tools/Scripts/webkitpy/tool/commands/__init__.py
@@ -10,5 +10,6 @@ from webkitpy.tool.commands.queries import *
from webkitpy.tool.commands.queues import *
from webkitpy.tool.commands.rebaseline import Rebaseline
from webkitpy.tool.commands.rebaselineserver import RebaselineServer
+from webkitpy.tool.commands.roll import *
from webkitpy.tool.commands.sheriffbot import *
from webkitpy.tool.commands.upload import *
diff --git a/Tools/Scripts/webkitpy/tool/commands/commandtest.py b/Tools/Scripts/webkitpy/tool/commands/commandtest.py
index c0efa50..e335710 100644
--- a/Tools/Scripts/webkitpy/tool/commands/commandtest.py
+++ b/Tools/Scripts/webkitpy/tool/commands/commandtest.py
@@ -32,7 +32,7 @@ from webkitpy.common.system.outputcapture import OutputCapture
from webkitpy.tool.mocktool import MockOptions, MockTool
class CommandsTest(unittest.TestCase):
- def assert_execute_outputs(self, command, args, expected_stdout="", expected_stderr="", options=MockOptions(), tool=MockTool()):
+ def assert_execute_outputs(self, command, args, expected_stdout="", expected_stderr="", expected_exception=None, options=MockOptions(), tool=MockTool()):
options.blocks = None
options.cc = 'MOCK cc'
options.component = 'MOCK component'
@@ -45,4 +45,4 @@ class CommandsTest(unittest.TestCase):
options.quiet = True
options.reviewer = 'MOCK reviewer'
command.bind_to_tool(tool)
- OutputCapture().assert_outputs(self, command.execute, [options, args, tool], expected_stdout=expected_stdout, expected_stderr=expected_stderr)
+ OutputCapture().assert_outputs(self, command.execute, [options, args, tool], expected_stdout=expected_stdout, expected_stderr=expected_stderr, expected_exception=expected_exception)
diff --git a/Tools/Scripts/webkitpy/tool/commands/download.py b/Tools/Scripts/webkitpy/tool/commands/download.py
index 1b478bf..35484cd 100644
--- a/Tools/Scripts/webkitpy/tool/commands/download.py
+++ b/Tools/Scripts/webkitpy/tool/commands/download.py
@@ -29,7 +29,7 @@
import os
-import webkitpy.tool.steps as steps
+from webkitpy.tool import steps
from webkitpy.common.checkout.changelog import ChangeLog
from webkitpy.common.config import urls
diff --git a/Tools/Scripts/webkitpy/tool/commands/download_unittest.py b/Tools/Scripts/webkitpy/tool/commands/download_unittest.py
index ba23ab9..ced5b2f 100644
--- a/Tools/Scripts/webkitpy/tool/commands/download_unittest.py
+++ b/Tools/Scripts/webkitpy/tool/commands/download_unittest.py
@@ -200,7 +200,13 @@ where ATTACHMENT_ID is the ID of this attachment.
self.assert_execute_outputs(CreateRollout(), ["855 852 854", "Reason"], options=self._default_options(), expected_stderr=expected_stderr)
def test_rollout(self):
- expected_stderr = "Preparing rollout for bug 42.\nUpdating working directory\nRunning prepare-ChangeLog\nMOCK: user.open_url: file://...\nBuilding WebKit\nCommitted r49824: <http://trac.webkit.org/changeset/49824>\n"
- expected_stdout = "Was that diff correct?\n"
- self.assert_execute_outputs(Rollout(), [852, "Reason"], options=self._default_options(), expected_stdout=expected_stdout, expected_stderr=expected_stderr)
+ expected_stderr = """Preparing rollout for bug 42.
+Updating working directory
+Running prepare-ChangeLog
+MOCK: user.open_url: file://...
+Was that diff correct?
+Building WebKit
+Committed r49824: <http://trac.webkit.org/changeset/49824>
+"""
+ self.assert_execute_outputs(Rollout(), [852, "Reason"], options=self._default_options(), expected_stderr=expected_stderr)
diff --git a/Tools/Scripts/webkitpy/tool/commands/prettydiff.py b/Tools/Scripts/webkitpy/tool/commands/prettydiff.py
index e3fc00c..67866f0 100644
--- a/Tools/Scripts/webkitpy/tool/commands/prettydiff.py
+++ b/Tools/Scripts/webkitpy/tool/commands/prettydiff.py
@@ -27,7 +27,7 @@
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
from webkitpy.tool.commands.abstractsequencedcommand import AbstractSequencedCommand
-import webkitpy.tool.steps as steps
+from webkitpy.tool import steps
class PrettyDiff(AbstractSequencedCommand):
diff --git a/Tools/Scripts/webkitpy/tool/commands/queries.py b/Tools/Scripts/webkitpy/tool/commands/queries.py
index 733751e..57f90ae 100644
--- a/Tools/Scripts/webkitpy/tool/commands/queries.py
+++ b/Tools/Scripts/webkitpy/tool/commands/queries.py
@@ -30,7 +30,7 @@
from optparse import make_option
-import webkitpy.tool.steps as steps
+from webkitpy.tool import steps
from webkitpy.common.checkout.commitinfo import CommitInfo
from webkitpy.common.config.committers import CommitterList
diff --git a/Tools/Scripts/webkitpy/tool/commands/roll.py b/Tools/Scripts/webkitpy/tool/commands/roll.py
new file mode 100644
index 0000000..0cf95e9
--- /dev/null
+++ b/Tools/Scripts/webkitpy/tool/commands/roll.py
@@ -0,0 +1,48 @@
+# Copyright (c) 2011 Google Inc. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+# * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+from webkitpy.tool.commands.abstractsequencedcommand import AbstractSequencedCommand
+
+from webkitpy.tool import steps
+
+
+class RollChromiumDEPS(AbstractSequencedCommand):
+ name = "roll-chromium-deps"
+ help_text = "Updates Chromium DEPS (defaults to the last-known good revision of Chromium)"
+ argument_names = "[CHROMIUM_REVISION]"
+ steps = [
+ steps.UpdateChromiumDEPS,
+ steps.PrepareChangeLogForDEPSRoll,
+ steps.ConfirmDiff,
+ steps.Commit,
+ ]
+
+ def _prepare_state(self, options, args, tool):
+ return {
+ "chromium_revision": (args and args[0]),
+ }
diff --git a/Tools/Scripts/webkitpy/tool/commands/roll_unittest.py b/Tools/Scripts/webkitpy/tool/commands/roll_unittest.py
new file mode 100644
index 0000000..b6f69ea
--- /dev/null
+++ b/Tools/Scripts/webkitpy/tool/commands/roll_unittest.py
@@ -0,0 +1,50 @@
+# Copyright (C) 2011 Google Inc. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+# * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+from webkitpy.thirdparty.mock import Mock
+from webkitpy.tool.commands.commandtest import CommandsTest
+from webkitpy.tool.commands.roll import *
+from webkitpy.tool.mocktool import MockOptions, MockTool
+
+
+class RollCommandsTest(CommandsTest):
+ def test_update_chromium_deps(self):
+ expected_stderr = """Updating Chromium DEPS to 6764
+MOCK: MockDEPS.write_variable(chromium_rev, 6764)
+Running prepare-ChangeLog
+MOCK: user.open_url: file://...
+Was that diff correct?
+Committed r49824: <http://trac.webkit.org/changeset/49824>
+"""
+ self.assert_execute_outputs(RollChromiumDEPS(), [6764], expected_stderr=expected_stderr)
+
+ def test_update_chromium_deps_older_revision(self):
+ expected_stderr = """Current Chromium DEPS revision 6564 is newer than 5764.
+ERROR: Unable to update Chromium DEPS
+"""
+ self.assert_execute_outputs(RollChromiumDEPS(), [5764], expected_stderr=expected_stderr, expected_exception=SystemExit)
diff --git a/Tools/Scripts/webkitpy/tool/commands/stepsequence.py b/Tools/Scripts/webkitpy/tool/commands/stepsequence.py
index be2ed4c..b666554 100644
--- a/Tools/Scripts/webkitpy/tool/commands/stepsequence.py
+++ b/Tools/Scripts/webkitpy/tool/commands/stepsequence.py
@@ -26,12 +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 webkitpy.tool.steps as steps
+from webkitpy.tool import steps
-from webkitpy.common.system.executive import ScriptError
from webkitpy.common.checkout.scm import CheckoutNeedsUpdate
-from webkitpy.tool.bot.queueengine import QueueEngine
from webkitpy.common.system.deprecated_logging import log
+from webkitpy.common.system.executive import ScriptError
+from webkitpy.tool.bot.queueengine import QueueEngine
class StepSequenceErrorHandler():
diff --git a/Tools/Scripts/webkitpy/tool/commands/upload.py b/Tools/Scripts/webkitpy/tool/commands/upload.py
index 6617b4f..e455b18 100644
--- a/Tools/Scripts/webkitpy/tool/commands/upload.py
+++ b/Tools/Scripts/webkitpy/tool/commands/upload.py
@@ -34,17 +34,17 @@ import sys
from optparse import make_option
-import webkitpy.tool.steps as steps
+from webkitpy.tool import steps
from webkitpy.common.config.committers import CommitterList
from webkitpy.common.net.bugzilla import parse_bug_id
+from webkitpy.common.system.deprecated_logging import error, log
from webkitpy.common.system.user import User
from webkitpy.thirdparty.mock import Mock
from webkitpy.tool.commands.abstractsequencedcommand import AbstractSequencedCommand
-from webkitpy.tool.grammar import pluralize, join_with_separators
from webkitpy.tool.comments import bug_comment_from_svn_revision
+from webkitpy.tool.grammar import pluralize, join_with_separators
from webkitpy.tool.multicommandtool import AbstractDeclarativeCommand
-from webkitpy.common.system.deprecated_logging import error, log
class CommitMessageForCurrentDiff(AbstractDeclarativeCommand):
diff --git a/Tools/Scripts/webkitpy/tool/commands/upload_unittest.py b/Tools/Scripts/webkitpy/tool/commands/upload_unittest.py
index a347b00..b5f5ae9 100644
--- a/Tools/Scripts/webkitpy/tool/commands/upload_unittest.py
+++ b/Tools/Scripts/webkitpy/tool/commands/upload_unittest.py
@@ -61,12 +61,12 @@ class UploadCommandsTest(CommandsTest):
options.suggest_reviewers = False
expected_stderr = """Running check-webkit-style
MOCK: user.open_url: file://...
+Was that diff correct?
Obsoleting 2 old patches on bug 42
MOCK add_patch_to_bug: bug_id=42, description=MOCK description, mark_for_review=True, mark_for_commit_queue=False, mark_for_landing=False
MOCK: user.open_url: http://example.com/42
"""
- expected_stdout = "Was that diff correct?\n"
- self.assert_execute_outputs(Post(), [42], options=options, expected_stdout=expected_stdout, expected_stderr=expected_stderr)
+ self.assert_execute_outputs(Post(), [42], options=options, expected_stderr=expected_stderr)
def test_land_safely(self):
expected_stderr = "Obsoleting 2 old patches on bug 42\nMOCK add_patch_to_bug: bug_id=42, description=Patch for landing, mark_for_review=False, mark_for_commit_queue=False, mark_for_landing=True\n"
@@ -90,12 +90,12 @@ MOCK: user.open_url: http://example.com/42
options.suggest_reviewers = False
expected_stderr = """Running check-webkit-style
MOCK: user.open_url: file://...
+Was that diff correct?
Obsoleting 2 old patches on bug 42
MOCK add_patch_to_bug: bug_id=42, description=MOCK description, mark_for_review=True, mark_for_commit_queue=False, mark_for_landing=False
MOCK: user.open_url: http://example.com/42
"""
- expected_stdout = "Was that diff correct?\n"
- self.assert_execute_outputs(Upload(), [42], options=options, expected_stdout=expected_stdout, expected_stderr=expected_stderr)
+ self.assert_execute_outputs(Upload(), [42], options=options, expected_stderr=expected_stderr)
def test_mark_bug_fixed(self):
tool = MockTool()
@@ -106,6 +106,7 @@ MOCK: user.open_url: http://example.com/42
expected_stderr = """Bug: <http://example.com/42> Bug with two r+'d and cq+'d patches, one of which has an invalid commit-queue setter.
Revision: 9876
MOCK: user.open_url: http://example.com/42
+Is this correct?
Adding comment to Bug 42.
MOCK bug comment: bug_id=42, cc=None
--- Begin comment ---
@@ -115,8 +116,7 @@ Committed r9876: <http://trac.webkit.org/changeset/9876>
--- End comment ---
"""
- expected_stdout = "Is this correct?\n"
- self.assert_execute_outputs(MarkBugFixed(), [], expected_stdout=expected_stdout, expected_stderr=expected_stderr, tool=tool, options=options)
+ self.assert_execute_outputs(MarkBugFixed(), [], expected_stderr=expected_stderr, tool=tool, options=options)
def test_edit_changelog(self):
self.assert_execute_outputs(EditChangeLogs(), [])
diff --git a/Tools/Scripts/webkitpy/tool/main.py b/Tools/Scripts/webkitpy/tool/main.py
index 6b07615..25cb9f9 100755
--- a/Tools/Scripts/webkitpy/tool/main.py
+++ b/Tools/Scripts/webkitpy/tool/main.py
@@ -44,7 +44,7 @@ from webkitpy.common.net.statusserver import StatusServer
from webkitpy.common.system import executive, filesystem, platforminfo, user, workspace
from webkitpy.layout_tests import port
from webkitpy.tool.multicommandtool import MultiCommandTool
-import webkitpy.tool.commands as commands
+from webkitpy.tool import commands
class WebKitPatch(MultiCommandTool, Host):
diff --git a/Tools/Scripts/webkitpy/tool/mocktool.py b/Tools/Scripts/webkitpy/tool/mocktool.py
index 7db2996..73f55a7 100644
--- a/Tools/Scripts/webkitpy/tool/mocktool.py
+++ b/Tools/Scripts/webkitpy/tool/mocktool.py
@@ -464,6 +464,12 @@ class MockSCM(Mock):
# os.getcwd() can't work here because other parts of the code assume that "checkout_root"
# will actually be the root. Since getcwd() is wrong, use a globally fake root for now.
self.checkout_root = self.fake_checkout_root
+ self.added_paths = set()
+
+ def add(self, destination_path, return_exit_code=False):
+ self.added_paths.add(destination_path)
+ if return_exit_code:
+ return 0
def changed_files(self, git_commit=None):
return ["MockFile1"]
@@ -483,16 +489,26 @@ class MockSCM(Mock):
"https://bugs.example.org/show_bug.cgi?id=75\n")
raise Exception("Bogus commit_id in commit_message_for_local_commit.")
+ def diff_for_file(self, path, log=None):
+ return path + '-diff'
+
def diff_for_revision(self, revision):
return "DiffForRevision%s\n" \
"http://bugs.webkit.org/show_bug.cgi?id=12345" % revision
+ def show_head(self, path):
+ return path
+
def svn_revision_from_commit_text(self, commit_text):
return "49824"
- def add(self, destination_path, return_exit_code=False):
- if return_exit_code:
- return 0
+
+class MockDEPS(object):
+ def read_variable(self, name):
+ return 6564
+
+ def write_variable(self, name, value):
+ log("MOCK: MockDEPS.write_variable(%s, %s)" % (name, value))
class MockCheckout(object):
@@ -528,6 +544,9 @@ class MockCheckout(object):
commit_message.message = lambda:"This is a fake commit message that is at least 50 characters."
return commit_message
+ def chromium_deps(self):
+ return MockDEPS()
+
def apply_patch(self, patch, force=False):
pass
@@ -548,6 +567,9 @@ class MockUser(object):
def prompt_with_list(cls, list_title, list_items, can_choose_multiple=False, raw_input=raw_input):
pass
+ def __init__(self):
+ self.opened_urls = []
+
def edit(self, files):
pass
@@ -558,13 +580,14 @@ class MockUser(object):
pass
def confirm(self, message=None, default='y'):
- print message
+ log(message)
return default == 'y'
def can_open_url(self):
return True
def open_url(self, url):
+ self.opened_urls.append(url)
if url.startswith("file://"):
log("MOCK: user.open_url: file://...")
return
diff --git a/Tools/Scripts/webkitpy/tool/steps/__init__.py b/Tools/Scripts/webkitpy/tool/steps/__init__.py
index f426f17..d5d7bb4 100644
--- a/Tools/Scripts/webkitpy/tool/steps/__init__.py
+++ b/Tools/Scripts/webkitpy/tool/steps/__init__.py
@@ -47,6 +47,7 @@ from webkitpy.tool.steps.options import Options
from webkitpy.tool.steps.postdiff import PostDiff
from webkitpy.tool.steps.postdiffforcommit import PostDiffForCommit
from webkitpy.tool.steps.postdiffforrevert import PostDiffForRevert
+from webkitpy.tool.steps.preparechangelogfordepsroll import PrepareChangeLogForDEPSRoll
from webkitpy.tool.steps.preparechangelogforrevert import PrepareChangeLogForRevert
from webkitpy.tool.steps.preparechangelog import PrepareChangeLog
from webkitpy.tool.steps.promptforbugortitle import PromptForBugOrTitle
@@ -55,6 +56,7 @@ from webkitpy.tool.steps.revertrevision import RevertRevision
from webkitpy.tool.steps.runtests import RunTests
from webkitpy.tool.steps.suggestreviewers import SuggestReviewers
from webkitpy.tool.steps.updatechangelogswithreviewer import UpdateChangeLogsWithReviewer
+from webkitpy.tool.steps.updatechromiumdeps import UpdateChromiumDEPS
from webkitpy.tool.steps.update import Update
from webkitpy.tool.steps.validatechangelogs import ValidateChangeLogs
from webkitpy.tool.steps.validatereviewer import ValidateReviewer
diff --git a/Tools/Scripts/webkitpy/tool/steps/preparechangelogfordepsroll.py b/Tools/Scripts/webkitpy/tool/steps/preparechangelogfordepsroll.py
new file mode 100644
index 0000000..39c9a9a
--- /dev/null
+++ b/Tools/Scripts/webkitpy/tool/steps/preparechangelogfordepsroll.py
@@ -0,0 +1,40 @@
+# Copyright (C) 2011 Google Inc. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+# * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+import os
+
+from webkitpy.common.checkout.changelog import ChangeLog
+from webkitpy.tool.steps.abstractstep import AbstractStep
+
+
+class PrepareChangeLogForDEPSRoll(AbstractStep):
+ def run(self, state):
+ self._run_script("prepare-ChangeLog")
+ changelog_paths = self._tool.checkout().modified_changelogs(git_commit=None)
+ for changelog_path in changelog_paths:
+ ChangeLog(changelog_path).update_with_unreviewed_message("Rolled DEPS.\n\n")
diff --git a/Tools/Scripts/webkitpy/tool/steps/preparechangelogforrevert.py b/Tools/Scripts/webkitpy/tool/steps/preparechangelogforrevert.py
index 1e47a6a..dcd4b93 100644
--- a/Tools/Scripts/webkitpy/tool/steps/preparechangelogforrevert.py
+++ b/Tools/Scripts/webkitpy/tool/steps/preparechangelogforrevert.py
@@ -29,16 +29,32 @@
import os
from webkitpy.common.checkout.changelog import ChangeLog
+from webkitpy.common.config import urls
+from webkitpy.tool.grammar import join_with_separators
from webkitpy.tool.steps.abstractstep import AbstractStep
class PrepareChangeLogForRevert(AbstractStep):
+ @classmethod
+ def _message_for_revert(cls, revision_list, reason, bug_url=None):
+ message = "Unreviewed, rolling out %s.\n" % join_with_separators(['r' + str(revision) for revision in revision_list])
+ for revision in revision_list:
+ message += "%s\n" % urls.view_revision_url(revision)
+ if bug_url:
+ message += "%s\n" % bug_url
+ # Add an extra new line after the rollout links, before any reason.
+ message += "\n"
+ if reason:
+ message += "%s\n\n" % reason
+ return message
+
def run(self, state):
# This could move to prepare-ChangeLog by adding a --revert= option.
self._run_script("prepare-ChangeLog")
changelog_paths = self._tool.checkout().modified_changelogs(git_commit=None)
bug_url = self._tool.bugs.bug_url_for_bug_id(state["bug_id"]) if state["bug_id"] else None
+ message = self._message_for_revert(state["revision_list"], state["reason"], bug_url)
for changelog_path in changelog_paths:
# FIXME: Seems we should prepare the message outside of changelogs.py and then just pass in
# text that we want to use to replace the reviewed by line.
- ChangeLog(changelog_path).update_for_revert(state["revision_list"], state["reason"], bug_url)
+ ChangeLog(changelog_path).update_with_unreviewed_message(message)
diff --git a/Tools/Scripts/webkitpy/tool/steps/preparechangelogforrevert_unittest.py b/Tools/Scripts/webkitpy/tool/steps/preparechangelogforrevert_unittest.py
new file mode 100644
index 0000000..aa9d5e9
--- /dev/null
+++ b/Tools/Scripts/webkitpy/tool/steps/preparechangelogforrevert_unittest.py
@@ -0,0 +1,130 @@
+# Copyright (C) 2011 Google Inc. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+# * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+from __future__ import with_statement
+
+import codecs
+import os
+import tempfile
+import unittest
+
+from webkitpy.common.checkout.changelog import ChangeLog
+from webkitpy.common.checkout.changelog_unittest import ChangeLogTest
+from webkitpy.tool.steps.preparechangelogforrevert import *
+
+
+class UpdateChangeLogsForRevertTest(unittest.TestCase):
+ @staticmethod
+ def _write_tmp_file_with_contents(byte_array):
+ assert(isinstance(byte_array, str))
+ (file_descriptor, file_path) = tempfile.mkstemp() # NamedTemporaryFile always deletes the file on close in python < 2.6
+ with os.fdopen(file_descriptor, "w") as file:
+ file.write(byte_array)
+ return file_path
+
+ _revert_entry_with_bug_url = '''2009-08-19 Eric Seidel <eric@webkit.org>
+
+ Unreviewed, rolling out r12345.
+ http://trac.webkit.org/changeset/12345
+ http://example.com/123
+
+ Reason
+
+ * Scripts/bugzilla-tool:
+'''
+
+ _revert_entry_without_bug_url = '''2009-08-19 Eric Seidel <eric@webkit.org>
+
+ Unreviewed, rolling out r12345.
+ http://trac.webkit.org/changeset/12345
+
+ Reason
+
+ * Scripts/bugzilla-tool:
+'''
+
+ _multiple_revert_entry_with_bug_url = '''2009-08-19 Eric Seidel <eric@webkit.org>
+
+ Unreviewed, rolling out r12345, r12346, and r12347.
+ http://trac.webkit.org/changeset/12345
+ http://trac.webkit.org/changeset/12346
+ http://trac.webkit.org/changeset/12347
+ http://example.com/123
+
+ Reason
+
+ * Scripts/bugzilla-tool:
+'''
+
+ _multiple_revert_entry_without_bug_url = '''2009-08-19 Eric Seidel <eric@webkit.org>
+
+ Unreviewed, rolling out r12345, r12346, and r12347.
+ http://trac.webkit.org/changeset/12345
+ http://trac.webkit.org/changeset/12346
+ http://trac.webkit.org/changeset/12347
+
+ Reason
+
+ * Scripts/bugzilla-tool:
+'''
+
+ _revert_with_log_reason = """2009-08-19 Eric Seidel <eric@webkit.org>
+
+ Unreviewed, rolling out r12345.
+ http://trac.webkit.org/changeset/12345
+ http://example.com/123
+
+ This is a very long reason which should be long enough so that
+ _message_for_revert will need to wrap it. We'll also include
+ a
+ https://veryveryveryveryverylongbugurl.com/reallylongbugthingy.cgi?bug_id=12354
+ link so that we can make sure we wrap that right too.
+
+ * Scripts/bugzilla-tool:
+"""
+
+ def _assert_message_for_revert_output(self, args, expected_entry):
+ changelog_contents = u"%s\n%s" % (ChangeLogTest._new_entry_boilerplate, ChangeLogTest._example_changelog)
+ changelog_path = self._write_tmp_file_with_contents(changelog_contents.encode("utf-8"))
+ changelog = ChangeLog(changelog_path)
+ changelog.update_with_unreviewed_message(PrepareChangeLogForRevert._message_for_revert(*args))
+ actual_entry = changelog.latest_entry()
+ os.remove(changelog_path)
+ self.assertEquals(actual_entry.contents(), expected_entry)
+ self.assertEquals(actual_entry.reviewer_text(), None)
+ # These checks could be removed to allow this to work on other entries:
+ self.assertEquals(actual_entry.author_name(), "Eric Seidel")
+ self.assertEquals(actual_entry.author_email(), "eric@webkit.org")
+
+ def test_message_for_revert(self):
+ self._assert_message_for_revert_output([[12345], "Reason"], self._revert_entry_without_bug_url)
+ self._assert_message_for_revert_output([[12345], "Reason", "http://example.com/123"], self._revert_entry_with_bug_url)
+ self._assert_message_for_revert_output([[12345, 12346, 12347], "Reason"], self._multiple_revert_entry_without_bug_url)
+ self._assert_message_for_revert_output([[12345, 12346, 12347], "Reason", "http://example.com/123"], self._multiple_revert_entry_with_bug_url)
+ long_reason = "This is a very long reason which should be long enough so that _message_for_revert will need to wrap it. We'll also include a https://veryveryveryveryverylongbugurl.com/reallylongbugthingy.cgi?bug_id=12354 link so that we can make sure we wrap that right too."
+ self._assert_message_for_revert_output([[12345], long_reason, "http://example.com/123"], self._revert_with_log_reason)
diff --git a/Tools/Scripts/webkitpy/tool/steps/suggestreviewers_unittest.py b/Tools/Scripts/webkitpy/tool/steps/suggestreviewers_unittest.py
index 0c86535..e995663 100644
--- a/Tools/Scripts/webkitpy/tool/steps/suggestreviewers_unittest.py
+++ b/Tools/Scripts/webkitpy/tool/steps/suggestreviewers_unittest.py
@@ -41,5 +41,6 @@ class SuggestReviewersTest(unittest.TestCase):
def test_basic(self):
capture = OutputCapture()
step = SuggestReviewers(MockTool(), MockOptions(suggest_reviewers=True, git_commit=None))
- expected_stdout = "The following reviewers have recently modified files in your patch:\nFoo Bar\nWould you like to CC them?\n"
- capture.assert_outputs(self, step.run, [{"bug_id": "123"}], expected_stdout=expected_stdout)
+ expected_stdout = "The following reviewers have recently modified files in your patch:\nFoo Bar\n"
+ expected_stderr = "Would you like to CC them?\n"
+ capture.assert_outputs(self, step.run, [{"bug_id": "123"}], expected_stdout=expected_stdout, expected_stderr=expected_stderr)
diff --git a/Tools/Scripts/webkitpy/tool/steps/updatechromiumdeps.py b/Tools/Scripts/webkitpy/tool/steps/updatechromiumdeps.py
new file mode 100644
index 0000000..315bbac
--- /dev/null
+++ b/Tools/Scripts/webkitpy/tool/steps/updatechromiumdeps.py
@@ -0,0 +1,64 @@
+# Copyright (C) 2011 Google Inc. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+# * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+import urllib2
+
+from webkitpy.tool.steps.abstractstep import AbstractStep
+from webkitpy.tool.steps.options import Options
+from webkitpy.common.config import urls
+from webkitpy.common.system.deprecated_logging import log, error
+
+
+class UpdateChromiumDEPS(AbstractStep):
+ # Notice that this method throws lots of exciting exceptions!
+ def _fetch_last_known_good_revision(self):
+ return int(urllib2.urlopen(urls.chromium_lkgr_url).read())
+
+ def _validate_revisions(self, current_chromium_revision, new_chromium_revision):
+ if new_chromium_revision < current_chromium_revision:
+ log("Current Chromium DEPS revision %s is newer than %s." % (current_chromium_revision, new_chromium_revision))
+ new_chromium_revision = self._tool.user.prompt("Enter new chromium revision (enter nothing to cancel):\n")
+ try:
+ new_chromium_revision = int(new_chromium_revision)
+ except ValueError, TypeError:
+ new_chromium_revision = None
+ if not new_chromium_revision:
+ error("Unable to update Chromium DEPS")
+
+
+ def run(self, state):
+ # Note that state["chromium_revision"] must be defined, but can be None.
+ new_chromium_revision = state["chromium_revision"]
+ if not new_chromium_revision:
+ new_chromium_revision = self._fetch_last_known_good_revision()
+
+ deps = self._tool.checkout().chromium_deps()
+ current_chromium_revision = deps.read_variable("chromium_rev")
+ self._validate_revisions(current_chromium_revision, new_chromium_revision)
+ log("Updating Chromium DEPS to %s" % new_chromium_revision)
+ deps.write_variable("chromium_rev", new_chromium_revision)
diff --git a/Tools/Scripts/webkitpy/tool/steps/validatechangelogs_unittest.py b/Tools/Scripts/webkitpy/tool/steps/validatechangelogs_unittest.py
index db35a58..96bae9f 100644
--- a/Tools/Scripts/webkitpy/tool/steps/validatechangelogs_unittest.py
+++ b/Tools/Scripts/webkitpy/tool/steps/validatechangelogs_unittest.py
@@ -45,9 +45,8 @@ class ValidateChangeLogsTest(unittest.TestCase):
diff_file.lines = [(start_line, start_line, "foo")]
expected_stdout = expected_stderr = ""
if should_fail and not non_interactive:
- expected_stdout = "OK to continue?\n"
- expected_stderr = "The diff to mock/ChangeLog looks wrong. Are you sure your ChangeLog entry is at the top of the file?\n"
- result = OutputCapture().assert_outputs(self, step._check_changelog_diff, [diff_file], expected_stdout=expected_stdout, expected_stderr=expected_stderr)
+ expected_stderr = "The diff to mock/ChangeLog looks wrong. Are you sure your ChangeLog entry is at the top of the file?\nOK to continue?\n"
+ result = OutputCapture().assert_outputs(self, step._check_changelog_diff, [diff_file], expected_stderr=expected_stderr)
self.assertEqual(not result, should_fail)
def test_check_changelog_diff(self):
diff --git a/Tools/TestWebKitAPI/JavaScriptTest.cpp b/Tools/TestWebKitAPI/JavaScriptTest.cpp
new file mode 100644
index 0000000..08418c2
--- /dev/null
+++ b/Tools/TestWebKitAPI/JavaScriptTest.cpp
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2011 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "JavaScriptTest.h"
+
+#include "PlatformUtilities.h"
+#include "Test.h"
+#include <WebKit2/WKRetainPtr.h>
+
+namespace TestWebKitAPI {
+
+struct JavaScriptCallbackContext {
+ JavaScriptCallbackContext(const char* expectedString) : didFinish(false), expectedString(expectedString), didMatchExpectedString(false) { }
+
+ bool didFinish;
+ const char* expectedString;
+ bool didMatchExpectedString;
+};
+
+static void javaScriptCallback(WKStringRef string, WKErrorRef error, void* ctx)
+{
+ JavaScriptCallbackContext* context = static_cast<JavaScriptCallbackContext*>(ctx);
+
+ context->didFinish = true;
+ context->didMatchExpectedString = WKStringIsEqualToUTF8CString(string, context->expectedString);
+
+ TEST_ASSERT(!error);
+}
+
+static WKRetainPtr<WKStringRef> wk(const char* utf8String)
+{
+ return WKRetainPtr<WKStringRef>(AdoptWK, WKStringCreateWithUTF8CString(utf8String));
+}
+
+bool runJSTest(WKPageRef page, const char* script, const char* expectedResult)
+{
+ JavaScriptCallbackContext context(expectedResult);
+ WKPageRunJavaScriptInMainFrame(page, wk(script).get(), &context, javaScriptCallback);
+ Util::run(&context.didFinish);
+ return context.didMatchExpectedString;
+}
+
+} // namespace TestWebKitAPI
diff --git a/Tools/TestWebKitAPI/JavaScriptTest.h b/Tools/TestWebKitAPI/JavaScriptTest.h
new file mode 100644
index 0000000..e01fcd5
--- /dev/null
+++ b/Tools/TestWebKitAPI/JavaScriptTest.h
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2011 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+namespace TestWebKitAPI {
+
+// Executes |script| in the page and waits until it has run. Returns true if the script's output
+// matches |expectedResult|, false otherwise. Asserts if an error occurs.
+bool runJSTest(WKPageRef, const char* script, const char* expectedResult);
+
+} // namespace TestWebKitAPI
diff --git a/Tools/TestWebKitAPI/PlatformWebView.h b/Tools/TestWebKitAPI/PlatformWebView.h
index 43e329b..312168d 100644
--- a/Tools/TestWebKitAPI/PlatformWebView.h
+++ b/Tools/TestWebKitAPI/PlatformWebView.h
@@ -54,7 +54,7 @@ public:
PlatformWebView(WKContextRef, WKPageGroupRef = 0);
~PlatformWebView();
- WKPageRef page();
+ WKPageRef page() const;
PlatformWKView platformView() const { return m_view; }
void resizeTo(unsigned width, unsigned height);
void focus();
diff --git a/Tools/TestWebKitAPI/Test.h b/Tools/TestWebKitAPI/Test.h
index 93bfd8b..ed772d5 100644
--- a/Tools/TestWebKitAPI/Test.h
+++ b/Tools/TestWebKitAPI/Test.h
@@ -79,7 +79,9 @@ protected:
\
void TEST_CLASS_NAME(testSuite, testCaseName)::run()
-#define TEST_ASSERT(expression) do { if (!(expression)) { TestsController::shared().testFailed(__FILE__, __LINE__, #expression); return; } } while (0)
+#define _TEST_ASSERT_HELPER(expression, returnStatement) do { if (!(expression)) { TestsController::shared().testFailed(__FILE__, __LINE__, #expression); returnStatement; } } while (0)
+#define TEST_ASSERT(expression) _TEST_ASSERT_HELPER(expression, return)
+#define TEST_ASSERT_RETURN(expression, returnValue) _TEST_ASSERT_HELPER(expression, return (returnValue))
} // namespace TestWebKitAPI
diff --git a/Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj b/Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj
index 0aca686..99bb29f 100644
--- a/Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj
+++ b/Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj
@@ -45,6 +45,9 @@
C01A23F21266156700C9ED55 /* spacebar-scrolling.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = C02B7882126615410026BF0F /* spacebar-scrolling.html */; };
C02B77F2126612140026BF0F /* SpacebarScrolling.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C02B77F1126612140026BF0F /* SpacebarScrolling.cpp */; };
C02B7854126613AE0026BF0F /* Carbon.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C02B7853126613AE0026BF0F /* Carbon.framework */; };
+ C0ADBE7C12FCA4D000D2C129 /* JavaScriptTest.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C0ADBE7A12FCA4D000D2C129 /* JavaScriptTest.cpp */; };
+ C0ADBE8312FCA6AA00D2C129 /* RestoreSessionStateContainingFormData.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C0ADBE8212FCA6AA00D2C129 /* RestoreSessionStateContainingFormData.cpp */; };
+ C0ADBE9612FCA79B00D2C129 /* simple-form.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = C0ADBE8412FCA6B600D2C129 /* simple-form.html */; };
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
@@ -76,6 +79,7 @@
BCBD3737125ABBEB00D2C29F /* icon.png in Copy Resources */,
1A02C870125D4CFD00E3F4BD /* find.html in Copy Resources */,
BC909784125571CF00083756 /* simple.html in Copy Resources */,
+ C0ADBE9612FCA79B00D2C129 /* simple-form.html in Copy Resources */,
C01A23F21266156700C9ED55 /* spacebar-scrolling.html in Copy Resources */,
BC2D006412AA04CE00E732A3 /* file-with-anchor.html in Copy Resources */,
);
@@ -132,6 +136,10 @@
C02B77F1126612140026BF0F /* SpacebarScrolling.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SpacebarScrolling.cpp; sourceTree = "<group>"; };
C02B7853126613AE0026BF0F /* Carbon.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; name = Carbon.framework; sourceTree = SDKROOT; };
C02B7882126615410026BF0F /* spacebar-scrolling.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = "spacebar-scrolling.html"; sourceTree = "<group>"; };
+ C0ADBE7A12FCA4D000D2C129 /* JavaScriptTest.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JavaScriptTest.cpp; sourceTree = "<group>"; };
+ C0ADBE7B12FCA4D000D2C129 /* JavaScriptTest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JavaScriptTest.h; sourceTree = "<group>"; };
+ C0ADBE8212FCA6AA00D2C129 /* RestoreSessionStateContainingFormData.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = RestoreSessionStateContainingFormData.cpp; sourceTree = "<group>"; };
+ C0ADBE8412FCA6B600D2C129 /* simple-form.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = "simple-form.html"; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
@@ -177,6 +185,8 @@
children = (
BCA61C3A11700B9400460D1E /* mac */,
BC575944126E733C006F0F12 /* InjectedBundle */,
+ C0ADBE7A12FCA4D000D2C129 /* JavaScriptTest.cpp */,
+ C0ADBE7B12FCA4D000D2C129 /* JavaScriptTest.h */,
BC131A9E1171317C00B69727 /* TestWebKitAPIPrefix.h */,
BC575BBF126F5752006F0F12 /* PlatformUtilities.cpp */,
BC131883117114A800B69727 /* PlatformUtilities.h */,
@@ -246,6 +256,7 @@
BC909779125571AB00083756 /* PageLoadBasic.cpp */,
BC2D004812A9FDFA00E732A3 /* PageLoadDidChangeLocationWithinPageForFrame.cpp */,
333B9CE11277F23100FEFCE3 /* PreventEmptyUserAgent.cpp */,
+ C0ADBE8212FCA6AA00D2C129 /* RestoreSessionStateContainingFormData.cpp */,
C02B77F1126612140026BF0F /* SpacebarScrolling.cpp */,
BC7B619A1299FE9E00D174A4 /* WKPreferences.cpp */,
BC90995D12567BC100083756 /* WKString.cpp */,
@@ -269,6 +280,7 @@
1A02C84B125D4A5E00E3F4BD /* find.html */,
BCBD372E125ABBE600D2C29F /* icon.png */,
BC909778125571AB00083756 /* simple.html */,
+ C0ADBE8412FCA6B600D2C129 /* simple-form.html */,
C02B7882126615410026BF0F /* spacebar-scrolling.html */,
);
name = Resources;
@@ -393,6 +405,8 @@
333B9CE21277F23100FEFCE3 /* PreventEmptyUserAgent.cpp in Sources */,
BC7B61AA129A038700D174A4 /* WKPreferences.cpp in Sources */,
BC2D004912A9FDFA00E732A3 /* PageLoadDidChangeLocationWithinPageForFrame.cpp in Sources */,
+ C0ADBE7C12FCA4D000D2C129 /* JavaScriptTest.cpp in Sources */,
+ C0ADBE8312FCA6AA00D2C129 /* RestoreSessionStateContainingFormData.cpp in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2/PageLoadBasic.cpp b/Tools/TestWebKitAPI/Tests/WebKit2/PageLoadBasic.cpp
index 98a636c..6cd281e 100644
--- a/Tools/TestWebKitAPI/Tests/WebKit2/PageLoadBasic.cpp
+++ b/Tools/TestWebKitAPI/Tests/WebKit2/PageLoadBasic.cpp
@@ -87,7 +87,7 @@ static void didFinishLoadForFrame(WKPageRef page, WKFrameRef frame, WKTypeRef us
test1Done = true;
}
-static void decidePolicyForNavigationAction(WKPageRef page, WKFrameNavigationType navigationType, WKEventModifiers modifiers, WKEventMouseButton mouseButton, WKURLRef url, WKFrameRef frame, WKFramePolicyListenerRef listener, const void* clientInfo)
+static void decidePolicyForNavigationAction(WKPageRef page, WKFrameRef frame, WKFrameNavigationType navigationType, WKEventModifiers modifiers, WKEventMouseButton mouseButton, WKURLRequestRef request, WKFramePolicyListenerRef listener, WKTypeRef userData, const void* clientInfo)
{
State* state = reinterpret_cast<State*>(const_cast<void*>(clientInfo));
TEST_ASSERT(!state->didStartProvisionalLoadForFrame);
@@ -98,12 +98,12 @@ static void decidePolicyForNavigationAction(WKPageRef page, WKFrameNavigationTyp
WKFramePolicyListenerUse(listener);
}
-static void decidePolicyForNewWindowAction(WKPageRef page, WKFrameNavigationType navigationType, WKEventModifiers modifiers, WKEventMouseButton mouseButton, WKURLRef url, WKFrameRef frame, WKFramePolicyListenerRef listener, const void* clientInfo)
+static void decidePolicyForNewWindowAction(WKPageRef page, WKFrameRef frame, WKFrameNavigationType navigationType, WKEventModifiers modifiers, WKEventMouseButton mouseButton, WKURLRequestRef request, WKStringRef frameName, WKFramePolicyListenerRef listener, WKTypeRef userData, const void* clientInfo)
{
WKFramePolicyListenerUse(listener);
}
-static void decidePolicyForMIMEType(WKPageRef page, WKStringRef MIMEType, WKURLRef url, WKFrameRef frame, WKFramePolicyListenerRef listener, const void* clientInfo)
+static void decidePolicyForMIMEType(WKPageRef page, WKFrameRef frame, WKStringRef MIMEType, WKURLRequestRef request, WKFramePolicyListenerRef listener, WKTypeRef userData, const void* clientInfo)
{
WKFramePolicyListenerUse(listener);
}
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2/RestoreSessionStateContainingFormData.cpp b/Tools/TestWebKitAPI/Tests/WebKit2/RestoreSessionStateContainingFormData.cpp
new file mode 100644
index 0000000..7c08735
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WebKit2/RestoreSessionStateContainingFormData.cpp
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2011 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "Test.h"
+
+#include "JavaScriptTest.h"
+#include "PlatformUtilities.h"
+#include "PlatformWebView.h"
+
+namespace TestWebKitAPI {
+
+static bool didFinishLoad;
+
+static void didFinishLoadForFrame(WKPageRef, WKFrameRef, WKTypeRef, const void*)
+{
+ didFinishLoad = true;
+}
+
+static void setPageLoaderClient(WKPageRef page)
+{
+ WKPageLoaderClient loaderClient;
+ memset(&loaderClient, 0, sizeof(loaderClient));
+ loaderClient.version = 0;
+ loaderClient.didFinishLoadForFrame = didFinishLoadForFrame;
+
+ WKPageSetPageLoaderClient(page, &loaderClient);
+}
+
+static WKRetainPtr<WKDataRef> createSessionStateContainingFormData(WKContextRef context)
+{
+ PlatformWebView webView(context);
+ setPageLoaderClient(webView.page());
+
+ WKPageLoadURL(webView.page(), Util::adoptWK(Util::createURLForResource("simple-form", "html")).get());
+ Util::run(&didFinishLoad);
+ didFinishLoad = false;
+
+ TEST_ASSERT_RETURN(runJSTest(webView.page(), "submitForm()", "undefined"), 0);
+ Util::run(&didFinishLoad);
+ didFinishLoad = false;
+
+ return Util::adoptWK(WKPageCopySessionState(webView.page(), 0, 0));
+}
+
+TEST(WebKit2, RestoreSessionStateContainingFormData)
+{
+ WKRetainPtr<WKContextRef> context(AdoptWK, WKContextCreate());
+
+ // FIXME: Once <rdar://problem/8708435> is fixed, we can move the creation of this
+ // PlatformWebView after the call to createSessionStaetContainingFormData. Until then, it must
+ // remain here to avoid a race condition between the UI and web processes.
+ PlatformWebView webView(context.get());
+ setPageLoaderClient(webView.page());
+
+ WKRetainPtr<WKDataRef> data = createSessionStateContainingFormData(context.get());
+ TEST_ASSERT(data);
+
+ WKPageRestoreFromSessionState(webView.page(), data.get());
+ Util::run(&didFinishLoad);
+
+ TEST_ASSERT(WKPageCanGoBack(webView.page()));
+}
+
+} // namespace TestWebKitAPI
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2/SpacebarScrolling.cpp b/Tools/TestWebKitAPI/Tests/WebKit2/SpacebarScrolling.cpp
index 6d4783c..e3c6b20 100644
--- a/Tools/TestWebKitAPI/Tests/WebKit2/SpacebarScrolling.cpp
+++ b/Tools/TestWebKitAPI/Tests/WebKit2/SpacebarScrolling.cpp
@@ -25,20 +25,13 @@
#include "Test.h"
+#include "JavaScriptTest.h"
#include "PlatformUtilities.h"
#include "PlatformWebView.h"
#include <WebKit2/WKRetainPtr.h>
namespace TestWebKitAPI {
-struct JavaScriptCallbackContext {
- JavaScriptCallbackContext(const char* expectedString) : didFinish(false), expectedString(expectedString), didMatchExpectedString(false) { }
-
- bool didFinish;
- const char* expectedString;
- bool didMatchExpectedString;
-};
-
static bool didFinishLoad;
static bool didNotHandleKeyDownEvent;
@@ -53,29 +46,6 @@ static void didNotHandleKeyEventCallback(WKPageRef, WKNativeEventPtr event, cons
didNotHandleKeyDownEvent = true;
}
-static void javaScriptCallback(WKStringRef string, WKErrorRef error, void* ctx)
-{
- JavaScriptCallbackContext* context = static_cast<JavaScriptCallbackContext*>(ctx);
-
- context->didFinish = true;
- context->didMatchExpectedString = WKStringIsEqualToUTF8CString(string, context->expectedString);
-
- TEST_ASSERT(!error);
-}
-
-static WKRetainPtr<WKStringRef> wk(const char* utf8String)
-{
- return WKRetainPtr<WKStringRef>(AdoptWK, WKStringCreateWithUTF8CString(utf8String));
-}
-
-static bool runJSTest(WKPageRef page, const char* script, const char* expectedResult)
-{
- JavaScriptCallbackContext context(expectedResult);
- WKPageRunJavaScriptInMainFrame(page, wk(script).get(), &context, javaScriptCallback);
- Util::run(&context.didFinish);
- return context.didMatchExpectedString;
-}
-
TEST(WebKit2, SpacebarScrolling)
{
WKRetainPtr<WKContextRef> context(AdoptWK, WKContextCreate());
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2/simple-form.html b/Tools/TestWebKitAPI/Tests/WebKit2/simple-form.html
new file mode 100644
index 0000000..3bf1852
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WebKit2/simple-form.html
@@ -0,0 +1,11 @@
+<!DOCTYPE html>
+<script>
+function submitForm()
+{
+ document.forms[0].submit();
+}
+</script>
+<form method=post>
+<input name=foo value="Some unimportant data">
+<input type=submit>
+</form>
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2/win/HideFindIndicator.cpp b/Tools/TestWebKitAPI/Tests/WebKit2/win/HideFindIndicator.cpp
new file mode 100644
index 0000000..40d4f41
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WebKit2/win/HideFindIndicator.cpp
@@ -0,0 +1,85 @@
+/*
+ * 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 "Test.h"
+
+#include "PlatformUtilities.h"
+#include "PlatformWebView.h"
+
+namespace TestWebKitAPI {
+
+static bool didFinishLoad;
+static bool findIndicatorCallbackWasCalled;
+static HBITMAP bitmap;
+
+static void didFinishLoadForFrame(WKPageRef page, WKFrameRef frame, WKTypeRef userData, const void* clientInfo)
+{
+ didFinishLoad = true;
+}
+
+static void findIndicatorCallback(WKViewRef, HBITMAP selectionBitmap, RECT, bool, void*)
+{
+ findIndicatorCallbackWasCalled = true;
+ bitmap = selectionBitmap;
+}
+
+static void initialize(const PlatformWebView& webView)
+{
+ WKPageLoaderClient loaderClient;
+ memset(&loaderClient, 0, sizeof(loaderClient));
+
+ loaderClient.version = 0;
+ loaderClient.didFinishLoadForFrame = didFinishLoadForFrame;
+ WKPageSetPageLoaderClient(webView.page(), &loaderClient);
+
+ WKViewSetFindIndicatorCallback(webView.platformView(), findIndicatorCallback, 0);
+}
+
+TEST(WebKit2, HideFindIndicator)
+{
+ WKRetainPtr<WKContextRef> context(AdoptWK, WKContextCreate());
+ PlatformWebView webView(context.get());
+ initialize(webView);
+
+ WKRetainPtr<WKURLRef> url = Util::adoptWK(Util::createURLForResource("find", "html"));
+ WKPageLoadURL(webView.page(), url.get());
+ Util::run(&didFinishLoad);
+ didFinishLoad = false;
+
+ WKPageFindString(webView.page(), Util::toWK("Hello").get(), kWKFindOptionsShowFindIndicator, 100);
+ Util::run(&findIndicatorCallbackWasCalled);
+ findIndicatorCallbackWasCalled = false;
+
+ TEST_ASSERT(bitmap);
+ ::DeleteObject(bitmap);
+ bitmap = 0;
+
+ WKPageHideFindUI(webView.page());
+ Util::run(&findIndicatorCallbackWasCalled);
+
+ TEST_ASSERT(!bitmap);
+}
+
+} // namespace TestWebKitAPI
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2/win/ResizeViewWhileHidden.cpp b/Tools/TestWebKitAPI/Tests/WebKit2/win/ResizeViewWhileHidden.cpp
new file mode 100644
index 0000000..7310e6c
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WebKit2/win/ResizeViewWhileHidden.cpp
@@ -0,0 +1,125 @@
+/*
+ * Copyright (C) 2011 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "Test.h"
+
+#include "PlatformUtilities.h"
+#include "PlatformWebView.h"
+#include <WebKit2/WKRetainPtr.h>
+
+namespace TestWebKitAPI {
+
+static bool didFinishLoad;
+
+static void didFinishLoadForFrame(WKPageRef, WKFrameRef, WKTypeRef, const void*)
+{
+ didFinishLoad = true;
+}
+
+static void setPageLoaderClient(WKPageRef page)
+{
+ WKPageLoaderClient loaderClient;
+ memset(&loaderClient, 0, sizeof(loaderClient));
+ loaderClient.version = 0;
+ loaderClient.didFinishLoadForFrame = didFinishLoadForFrame;
+
+ WKPageSetPageLoaderClient(page, &loaderClient);
+}
+
+static void flushMessages(WKPageRef page)
+{
+ // In order to ensure all pending messages have been handled by the UI and web processes, we
+ // load a URL and wait for the load to finish.
+
+ setPageLoaderClient(page);
+
+ WKPageLoadURL(page, Util::adoptWK(Util::createURLForResource("simple", "html")).get());
+ Util::run(&didFinishLoad);
+ didFinishLoad = false;
+
+ WKPageSetPageLoaderClient(page, 0);
+}
+
+static bool timerFired;
+static void CALLBACK timerCallback(HWND hwnd, UINT, UINT_PTR timerID, DWORD)
+{
+ ::KillTimer(hwnd, timerID);
+ timerFired = true;
+}
+
+static void runForDuration(double seconds)
+{
+ ::SetTimer(0, 0, seconds * 1000, timerCallback);
+ Util::run(&timerFired);
+ timerFired = false;
+}
+
+static void waitForBackingStoreUpdate(WKPageRef page)
+{
+ // Wait for the web process to handle the changes we just made, to perform a display (which
+ // happens on a timer), and to tell the UI process about the display (which updates the backing
+ // store).
+ // FIXME: It would be much less fragile (and maybe faster) to have an explicit way to wait
+ // until the backing store is updated.
+ runForDuration(0.5);
+ flushMessages(page);
+}
+
+TEST(WebKit2, ResizeViewWhileHidden)
+{
+ WKRetainPtr<WKContextRef> context(AdoptWK, WKContextCreate());
+ PlatformWebView webView(context.get());
+
+ HWND window = WKViewGetWindow(webView.platformView());
+
+ RECT originalRect;
+ ::GetClientRect(window, &originalRect);
+ RECT newRect = originalRect;
+ ::InflateRect(&newRect, 1, 1);
+
+ // Show the WKView and resize it so that the WKView's backing store will be created. Ideally
+ // we'd have some more explicit way of forcing the backing store to be created.
+ ::ShowWindow(window, SW_SHOW);
+ webView.resizeTo(newRect.right - newRect.left, newRect.bottom - newRect.top);
+
+ waitForBackingStoreUpdate(webView.page());
+
+ // Resize the window while hidden and show it again so that it will update its backing store at
+ // the new size.
+ ::ShowWindow(window, SW_HIDE);
+ webView.resizeTo(originalRect.right - originalRect.left, originalRect.bottom - originalRect.top);
+ ::ShowWindow(window, SW_SHOW);
+
+ // Force the WKView to paint to try to trigger <http://webkit.org/b/54142>.
+ ::SendMessage(window, WM_PAINT, 0, 0);
+
+ // In Debug builds without the fix for <http://webkit.org/b/54141>, the web process will assert
+ // at this point.
+ // FIXME: It would be good to have a way to check that our behavior is correct in Release
+ // builds, too!
+ waitForBackingStoreUpdate(webView.page());
+}
+
+} // namespace TestWebKitAPI
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2/win/WMPrint.cpp b/Tools/TestWebKitAPI/Tests/WebKit2/win/WMPrint.cpp
new file mode 100644
index 0000000..390f161
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WebKit2/win/WMPrint.cpp
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2011 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "Test.h"
+
+#include "PlatformUtilities.h"
+#include "PlatformWebView.h"
+#include <WebKit2/WKRetainPtr.h>
+
+namespace TestWebKitAPI {
+
+TEST(WebKit2, WMPrint)
+{
+ WKRetainPtr<WKContextRef> context(AdoptWK, WKContextCreate());
+ PlatformWebView webView(context.get());
+
+ HWND window = WKViewGetWindow(webView.platformView());
+ HDC dc = ::CreateCompatibleDC(0);
+ // FIXME: It would be nice to test that this actually paints the view into dc.
+ ::SendMessage(window, WM_PRINT, reinterpret_cast<WPARAM>(dc), PRF_CLIENT | PRF_CHILDREN);
+ ::DeleteDC(dc);
+}
+
+} // namespace TestWebKitAPI
diff --git a/Tools/TestWebKitAPI/mac/PlatformWebViewMac.mm b/Tools/TestWebKitAPI/mac/PlatformWebViewMac.mm
index c4f2d72..ad901d3 100644
--- a/Tools/TestWebKitAPI/mac/PlatformWebViewMac.mm
+++ b/Tools/TestWebKitAPI/mac/PlatformWebViewMac.mm
@@ -55,7 +55,7 @@ PlatformWebView::~PlatformWebView()
[m_view release];
}
-WKPageRef PlatformWebView::page()
+WKPageRef PlatformWebView::page() const
{
return [m_view pageRef];
}
diff --git a/Tools/TestWebKitAPI/win/PlatformWebViewWin.cpp b/Tools/TestWebKitAPI/win/PlatformWebViewWin.cpp
index dede4b2..01a76eb 100644
--- a/Tools/TestWebKitAPI/win/PlatformWebViewWin.cpp
+++ b/Tools/TestWebKitAPI/win/PlatformWebViewWin.cpp
@@ -72,11 +72,16 @@ PlatformWebView::~PlatformWebView()
WKRelease(m_view);
}
-WKPageRef PlatformWebView::page()
+WKPageRef PlatformWebView::page() const
{
return WKViewGetPage(m_view);
}
+void PlatformWebView::resizeTo(unsigned width, unsigned height)
+{
+ ::SetWindowPos(WKViewGetWindow(m_view), 0, 0, 0, width, height, SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOCOPYBITS);
+}
+
void PlatformWebView::simulateSpacebarKeyPress()
{
HWND window = WKViewGetWindow(m_view);
diff --git a/Tools/TestWebKitAPI/win/TestWebKitAPI.vcproj b/Tools/TestWebKitAPI/win/TestWebKitAPI.vcproj
index a2412ef..0c806a8 100644
--- a/Tools/TestWebKitAPI/win/TestWebKitAPI.vcproj
+++ b/Tools/TestWebKitAPI/win/TestWebKitAPI.vcproj
@@ -456,6 +456,14 @@
>
</File>
<File
+ RelativePath="..\Tests\WebKit2\RestoreSessionStateContainingFormData.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\Tests\WebKit2\simple-form.html"
+ >
+ </File>
+ <File
RelativePath="..\Tests\WebKit2\simple.html"
>
</File>
@@ -487,6 +495,14 @@
>
</File>
<File
+ RelativePath="..\Tests\WebKit2\win\HideFindIndicator.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\Tests\WebKit2\win\ResizeViewWhileHidden.cpp"
+ >
+ </File>
+ <File
RelativePath="..\Tests\WebKit2\win\WMCloseCallsUIClientClose.cpp"
>
</File>
@@ -502,6 +518,14 @@
</Filter>
</Filter>
<File
+ RelativePath="..\JavaScriptTest.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\JavaScriptTest.h"
+ >
+ </File>
+ <File
RelativePath="..\PlatformUtilities.cpp"
>
</File>
diff --git a/Tools/TestWebKitAPI/win/copy-resources.cmd b/Tools/TestWebKitAPI/win/copy-resources.cmd
index dc56479..b0ef3df 100755
--- a/Tools/TestWebKitAPI/win/copy-resources.cmd
+++ b/Tools/TestWebKitAPI/win/copy-resources.cmd
@@ -12,6 +12,7 @@ for %%f in (
..\Tests\WebKit2\find.html
..\Tests\WebKit2\icon.png
..\Tests\WebKit2\simple.html
+ ..\Tests\WebKit2\simple-form.html
..\Tests\WebKit2\spacebar-scrolling.html
) do (
xcopy /y /d %%f "%ResourcesDirectory%"
diff --git a/Tools/Tools.pro b/Tools/Tools.pro
new file mode 100644
index 0000000..ca4ba3d
--- /dev/null
+++ b/Tools/Tools.pro
@@ -0,0 +1,15 @@
+TEMPLATE = subdirs
+CONFIG += ordered
+
+exists($$PWD/QtTestBrowser/QtTestBrowser.pro): SUBDIRS += QtTestBrowser/QtTestBrowser.pro
+exists($$PWD/DumpRenderTree/qt/DumpRenderTree.pro): SUBDIRS += DumpRenderTree/qt/DumpRenderTree.pro
+exists($$PWD/DumpRenderTree/qt/ImageDiff.pro): SUBDIRS += DumpRenderTree/qt/ImageDiff.pro
+
+webkit2 {
+ exists($$PWD/MiniBrowser/qt/MiniBrowser.pro): SUBDIRS += MiniBrowser/qt/MiniBrowser.pro
+ exists($$PWD/WebKitTestRunner/WebKitTestRunner.pro): SUBDIRS += WebKitTestRunner/WebKitTestRunner.pro
+}
+
+!win32:!symbian {
+ exists($$PWD/DumpRenderTree/qt/TestNetscapePlugin/TestNetscapePlugin.pro): SUBDIRS += DumpRenderTree/qt/TestNetscapePlugin/TestNetscapePlugin.pro
+}
diff --git a/Tools/WebKitTestRunner/Configurations/Base.xcconfig b/Tools/WebKitTestRunner/Configurations/Base.xcconfig
index feb7c5e..ac2ff94 100644
--- a/Tools/WebKitTestRunner/Configurations/Base.xcconfig
+++ b/Tools/WebKitTestRunner/Configurations/Base.xcconfig
@@ -21,7 +21,7 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-HEADER_SEARCH_PATHS = $(WEBCORE_PRIVATE_HEADERS_DIR)/ForwardingHeaders;
+HEADER_SEARCH_PATHS = $(WEBCORE_PRIVATE_HEADERS_DIR)/ForwardingHeaders ${SRCROOT}/../../Source/JavaScriptCore/icu;
FRAMEWORK_SEARCH_PATHS = $(SYSTEM_LIBRARY_DIR)/Frameworks/Quartz.framework/Frameworks $(SYSTEM_LIBRARY_DIR)/Frameworks/ApplicationServices.framework/Frameworks $(SYSTEM_LIBRARY_DIR)/Frameworks/CoreServices.framework/Frameworks;
GCC_PREPROCESSOR_DEFINITIONS = ENABLE_DASHBOARD_SUPPORT WEBKIT_VERSION_MIN_REQUIRED=WEBKIT_VERSION_LATEST;
DEBUG_INFORMATION_FORMAT = dwarf
diff --git a/Tools/WebKitTestRunner/DerivedSources.pro b/Tools/WebKitTestRunner/DerivedSources.pro
index 1e4e461..ce7ac63 100644
--- a/Tools/WebKitTestRunner/DerivedSources.pro
+++ b/Tools/WebKitTestRunner/DerivedSources.pro
@@ -34,7 +34,7 @@ defineTest(addExtraCompiler) {
return(true)
}
-SRC_ROOT_DIR = $$replace(PWD, /Tools/WebKitTestRunner, /)
+SRC_ROOT_DIR = $$replace(PWD, /Tools/WebKitTestRunner, "")
# Make sure forwarded headers needed by this project are present
fwheader_generator.commands = perl $${SRC_ROOT_DIR}/Source/WebKit2/Scripts/generate-forwarding-headers.pl $${SRC_ROOT_DIR}/Tools/WebKitTestRunner $${OUTPUT_DIR}/include qt
diff --git a/Tools/WebKitTestRunner/InjectedBundle/Bindings/LayoutTestController.idl b/Tools/WebKitTestRunner/InjectedBundle/Bindings/LayoutTestController.idl
index a88a838..a331c64 100644
--- a/Tools/WebKitTestRunner/InjectedBundle/Bindings/LayoutTestController.idl
+++ b/Tools/WebKitTestRunner/InjectedBundle/Bindings/LayoutTestController.idl
@@ -77,8 +77,18 @@ module WTR {
// Text search testing.
boolean findString(in DOMString target, in object optionsArray);
- // Evaluating script in a special context
- [PassContext] void evaluateScriptInIsolatedWorld(in unsigned long worldID, in DOMString script)
+ // Evaluating script in a special context.
+ [PassContext] void evaluateScriptInIsolatedWorld(in unsigned long worldID, in DOMString script);
+
+ // For Web Inspector tests
+ void showWebInspector();
+ void closeWebInspector();
+ void evaluateInWebInspector(in long callID, in DOMString script);
+ void setTimelineProfilingEnabled(in boolean enabled);
+
+ void setPOSIXLocale(in DOMString locale);
+
+ void setWillSendRequestReturnsNull(in boolean flag);
};
}
diff --git a/Tools/WebKitTestRunner/InjectedBundle/InjectedBundle.cpp b/Tools/WebKitTestRunner/InjectedBundle/InjectedBundle.cpp
index 972a606..d042431 100644
--- a/Tools/WebKitTestRunner/InjectedBundle/InjectedBundle.cpp
+++ b/Tools/WebKitTestRunner/InjectedBundle/InjectedBundle.cpp
@@ -118,6 +118,11 @@ InjectedBundlePage* InjectedBundle::page() const
return m_pages[0].get();
}
+void InjectedBundle::resetLocalSettings()
+{
+ setlocale(LC_ALL, "");
+}
+
void InjectedBundle::didReceiveMessage(WKStringRef messageName, WKTypeRef messageBody)
{
if (WKStringIsEqualToUTF8CString(messageName, "BeginTest")) {
@@ -131,6 +136,9 @@ void InjectedBundle::didReceiveMessage(WKStringRef messageName, WKTypeRef messag
return;
} else if (WKStringIsEqualToUTF8CString(messageName, "Reset")) {
m_state = Idle;
+
+ resetLocalSettings();
+
return;
}
diff --git a/Tools/WebKitTestRunner/InjectedBundle/InjectedBundle.h b/Tools/WebKitTestRunner/InjectedBundle/InjectedBundle.h
index 9778441..741ade4 100644
--- a/Tools/WebKitTestRunner/InjectedBundle/InjectedBundle.h
+++ b/Tools/WebKitTestRunner/InjectedBundle/InjectedBundle.h
@@ -82,6 +82,8 @@ private:
void didInitializePageGroup(WKBundlePageGroupRef);
void didReceiveMessage(WKStringRef messageName, WKTypeRef messageBody);
+ void resetLocalSettings();
+
void beginTesting();
WKBundleRef m_bundle;
diff --git a/Tools/WebKitTestRunner/InjectedBundle/InjectedBundlePage.cpp b/Tools/WebKitTestRunner/InjectedBundle/InjectedBundlePage.cpp
index c5f4909..739da3b 100644
--- a/Tools/WebKitTestRunner/InjectedBundle/InjectedBundlePage.cpp
+++ b/Tools/WebKitTestRunner/InjectedBundle/InjectedBundlePage.cpp
@@ -29,6 +29,7 @@
#include "StringFunctions.h"
#include <cmath>
#include <JavaScriptCore/JSRetainPtr.h>
+#include <WebCore/KURL.h>
#include <WebKit2/WKArray.h>
#include <WebKit2/WKBundle.h>
#include <WebKit2/WKBundleBackForwardList.h>
@@ -36,6 +37,7 @@
#include <WebKit2/WKBundleFrame.h>
#include <WebKit2/WKBundleFramePrivate.h>
#include <WebKit2/WKBundlePagePrivate.h>
+#include <WebKit2/WKURLRequest.h>
using namespace std;
@@ -190,9 +192,20 @@ InjectedBundlePage::InjectedBundlePage(WKBundlePageRef page)
didCancelClientRedirectForFrame,
willPerformClientRedirectForFrame,
didHandleOnloadEventsForFrame,
- shouldLoadResourceForFrame
};
- WKBundlePageSetLoaderClient(m_page, &loaderClient);
+ WKBundlePageSetPageLoaderClient(m_page, &loaderClient);
+
+ WKBundlePageResourceLoadClient resourceLoadClient = {
+ 0,
+ this,
+ didInitiateLoadForResource,
+ willSendRequestForFrame,
+ didReceiveResponseForResource,
+ didReceiveContentLengthForResource,
+ didFinishLoadForResource,
+ didFailLoadForResource
+ };
+ WKBundlePageSetResourceLoadClient(m_page, &resourceLoadClient);
WKBundlePageUIClient uiClient = {
0,
@@ -204,6 +217,7 @@ InjectedBundlePage::InjectedBundlePage(WKBundlePageRef page)
willRunJavaScriptPrompt,
0, /*mouseDidMoveOverElement*/
0, /*pageDidScroll*/
+ 0, /*paintCustomOverhangArea*/
};
WKBundlePageSetUIClient(m_page, &uiClient);
@@ -321,11 +335,35 @@ void InjectedBundlePage::didRunInsecureContentForFrame(WKBundlePageRef page, WKB
static_cast<InjectedBundlePage*>(const_cast<void*>(clientInfo))->didRunInsecureContentForFrame(frame);
}
-bool InjectedBundlePage::shouldLoadResourceForFrame(WKBundlePageRef page, WKBundleFrameRef frame, WKStringRef, const void* clientInfo)
+void InjectedBundlePage::didInitiateLoadForResource(WKBundlePageRef page, WKBundleFrameRef frame, uint64_t identifier, WKURLRequestRef request, bool pageLoadIsProvisional, const void* clientInfo)
+{
+ static_cast<InjectedBundlePage*>(const_cast<void*>(clientInfo))->didInitiateLoadForResource(page, frame, identifier, request, pageLoadIsProvisional);
+}
+
+WKURLRequestRef InjectedBundlePage::willSendRequestForFrame(WKBundlePageRef page, WKBundleFrameRef frame, uint64_t identifier, WKURLRequestRef request, WKURLResponseRef redirectResponse, const void* clientInfo)
+{
+ return static_cast<InjectedBundlePage*>(const_cast<void*>(clientInfo))->willSendRequestForFrame(page, frame, identifier, request, redirectResponse);
+}
+
+void InjectedBundlePage::didReceiveResponseForResource(WKBundlePageRef page, WKBundleFrameRef frame, uint64_t identifier, WKURLResponseRef response, const void* clientInfo)
{
- return static_cast<InjectedBundlePage*>(const_cast<void*>(clientInfo))->shouldLoadResourceForFrame(frame);
+ static_cast<InjectedBundlePage*>(const_cast<void*>(clientInfo))->didReceiveResponseForResource(page, frame, identifier, response);
}
+void InjectedBundlePage::didReceiveContentLengthForResource(WKBundlePageRef page, WKBundleFrameRef frame, uint64_t identifier, uint64_t length, const void* clientInfo)
+{
+ static_cast<InjectedBundlePage*>(const_cast<void*>(clientInfo))->didReceiveContentLengthForResource(page, frame, identifier, length);
+}
+
+void InjectedBundlePage::didFinishLoadForResource(WKBundlePageRef page, WKBundleFrameRef frame, uint64_t identifier, const void* clientInfo)
+{
+ static_cast<InjectedBundlePage*>(const_cast<void*>(clientInfo))->didFinishLoadForResource(page, frame, identifier);
+}
+
+void InjectedBundlePage::didFailLoadForResource(WKBundlePageRef page, WKBundleFrameRef frame, uint64_t identifier, WKErrorRef error, const void* clientInfo)
+{
+ static_cast<InjectedBundlePage*>(const_cast<void*>(clientInfo))->didFinishLoadForResource(page, frame, identifier, error);
+}
void InjectedBundlePage::didStartProvisionalLoadForFrame(WKBundleFrameRef frame)
{
@@ -574,9 +612,46 @@ void InjectedBundlePage::didRunInsecureContentForFrame(WKBundleFrameRef frame)
{
}
-bool InjectedBundlePage::shouldLoadResourceForFrame(WKBundleFrameRef frame)
+void InjectedBundlePage::didInitiateLoadForResource(WKBundlePageRef, WKBundleFrameRef, uint64_t identifier, WKURLRequestRef, bool)
+{
+}
+
+// Resource Load Client Callbacks
+
+WKURLRequestRef InjectedBundlePage::willSendRequestForFrame(WKBundlePageRef, WKBundleFrameRef, uint64_t, WKURLRequestRef request, WKURLResponseRef)
+{
+ if (InjectedBundle::shared().isTestRunning() && InjectedBundle::shared().layoutTestController()->willSendRequestReturnsNull())
+ return 0;
+
+ string urlString = toSTD(adoptWK(WKURLCopyString(adoptWK(WKURLRequestCopyURL(request)).get())));
+ WebCore::KURL url(WebCore::ParsedURLString, urlString.c_str());
+
+ if (!url.host().isEmpty()
+ && (equalIgnoringCase(url.protocol(), "http") || (equalIgnoringCase(url.protocol(), "https")))
+ && (url.host() != "127.0.0.1")
+ && (url.host() != "255.255.255.255") // used in some tests that expect to get back an error
+ && (!equalIgnoringCase(url.host(), "localhost"))) {
+ InjectedBundle::shared().os() << "Blocked access to external URL " << urlString << "\n";
+ return 0;
+ }
+
+ return request;
+}
+
+void InjectedBundlePage::didReceiveResponseForResource(WKBundlePageRef, WKBundleFrameRef, uint64_t, WKURLResponseRef)
+{
+}
+
+void InjectedBundlePage::didReceiveContentLengthForResource(WKBundlePageRef, WKBundleFrameRef, uint64_t, uint64_t)
+{
+}
+
+void InjectedBundlePage::didFinishLoadForResource(WKBundlePageRef, WKBundleFrameRef, uint64_t)
+{
+}
+
+void InjectedBundlePage::didFailLoadForResource(WKBundlePageRef, WKBundleFrameRef, uint64_t, WKErrorRef)
{
- return true;
}
// UI Client Callbacks
diff --git a/Tools/WebKitTestRunner/InjectedBundle/InjectedBundlePage.h b/Tools/WebKitTestRunner/InjectedBundle/InjectedBundlePage.h
index 3b99109..2c3e9df 100644
--- a/Tools/WebKitTestRunner/InjectedBundle/InjectedBundlePage.h
+++ b/Tools/WebKitTestRunner/InjectedBundle/InjectedBundlePage.h
@@ -63,7 +63,13 @@ private:
static void didHandleOnloadEventsForFrame(WKBundlePageRef, WKBundleFrameRef, const void*);
static void didDisplayInsecureContentForFrame(WKBundlePageRef, WKBundleFrameRef, WKTypeRef*, const void*);
static void didRunInsecureContentForFrame(WKBundlePageRef, WKBundleFrameRef, WKTypeRef*, const void*);
- static bool shouldLoadResourceForFrame(WKBundlePageRef, WKBundleFrameRef, WKStringRef, const void*);
+ static void didInitiateLoadForResource(WKBundlePageRef, WKBundleFrameRef, uint64_t identifier, WKURLRequestRef, bool pageLoadIsProvisional, const void*);
+ static WKURLRequestRef willSendRequestForFrame(WKBundlePageRef, WKBundleFrameRef, uint64_t identifier, WKURLRequestRef, WKURLResponseRef, const void*);
+ static void didReceiveResponseForResource(WKBundlePageRef, WKBundleFrameRef, uint64_t identifier, WKURLResponseRef, const void*);
+ static void didReceiveContentLengthForResource(WKBundlePageRef, WKBundleFrameRef, uint64_t identifier, uint64_t length, const void*);
+ static void didFinishLoadForResource(WKBundlePageRef, WKBundleFrameRef, uint64_t identifier, const void*);
+ static void didFailLoadForResource(WKBundlePageRef, WKBundleFrameRef, uint64_t identifier, WKErrorRef, const void*);
+
void didStartProvisionalLoadForFrame(WKBundleFrameRef);
void didReceiveServerRedirectForProvisionalLoadForFrame(WKBundleFrameRef);
void didFailProvisionalLoadWithErrorForFrame(WKBundleFrameRef, WKErrorRef);
@@ -79,7 +85,14 @@ private:
void didHandleOnloadEventsForFrame(WKBundleFrameRef);
void didDisplayInsecureContentForFrame(WKBundleFrameRef);
void didRunInsecureContentForFrame(WKBundleFrameRef);
- bool shouldLoadResourceForFrame(WKBundleFrameRef);
+
+ // Resource Load Client
+ void didInitiateLoadForResource(WKBundlePageRef, WKBundleFrameRef, uint64_t identifier, WKURLRequestRef, bool pageLoadIsProvisional);
+ WKURLRequestRef willSendRequestForFrame(WKBundlePageRef, WKBundleFrameRef, uint64_t identifier, WKURLRequestRef, WKURLResponseRef);
+ void didReceiveResponseForResource(WKBundlePageRef, WKBundleFrameRef, uint64_t identifier, WKURLResponseRef);
+ void didReceiveContentLengthForResource(WKBundlePageRef, WKBundleFrameRef, uint64_t identifier, uint64_t length);
+ void didFinishLoadForResource(WKBundlePageRef, WKBundleFrameRef, uint64_t identifier);
+ void didFailLoadForResource(WKBundlePageRef, WKBundleFrameRef, uint64_t identifier, WKErrorRef);
// UI Client
static void willAddMessageToConsole(WKBundlePageRef, WKStringRef message, uint32_t lineNumber, const void* clientInfo);
diff --git a/Tools/WebKitTestRunner/InjectedBundle/LayoutTestController.cpp b/Tools/WebKitTestRunner/InjectedBundle/LayoutTestController.cpp
index 13c7b10..4707ed8 100644
--- a/Tools/WebKitTestRunner/InjectedBundle/LayoutTestController.cpp
+++ b/Tools/WebKitTestRunner/InjectedBundle/LayoutTestController.cpp
@@ -32,6 +32,7 @@
#include <WebKit2/WKBundleBackForwardList.h>
#include <WebKit2/WKBundleFrame.h>
#include <WebKit2/WKBundleFramePrivate.h>
+#include <WebKit2/WKBundleInspector.h>
#include <WebKit2/WKBundlePagePrivate.h>
#include <WebKit2/WKBundleScriptWorld.h>
#include <WebKit2/WKBundlePrivate.h>
@@ -96,6 +97,7 @@ LayoutTestController::LayoutTestController()
, m_waitToDump(false)
, m_testRepaint(false)
, m_testRepaintSweepHorizontally(false)
+ , m_willSendRequestReturnsNull(false)
{
platformInitialize();
}
@@ -309,6 +311,27 @@ void LayoutTestController::makeWindowObject(JSContextRef context, JSObjectRef wi
setProperty(context, windowObject, "layoutTestController", this, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete, exception);
}
+void LayoutTestController::showWebInspector()
+{
+ WKBundleInspectorShow(WKBundlePageGetInspector(InjectedBundle::shared().page()->page()));
+}
+
+void LayoutTestController::closeWebInspector()
+{
+ WKBundleInspectorClose(WKBundlePageGetInspector(InjectedBundle::shared().page()->page()));
+}
+
+void LayoutTestController::evaluateInWebInspector(long callID, JSStringRef script)
+{
+ WKRetainPtr<WKStringRef> scriptWK = toWK(script);
+ WKBundleInspectorEvaluateScriptForTest(WKBundlePageGetInspector(InjectedBundle::shared().page()->page()), callID, scriptWK.get());
+}
+
+void LayoutTestController::setTimelineProfilingEnabled(bool enabled)
+{
+ WKBundleInspectorSetPageProfilingEnabled(WKBundlePageGetInspector(InjectedBundle::shared().page()->page()), enabled);
+}
+
typedef WTF::HashMap<unsigned, WKRetainPtr<WKBundleScriptWorldRef> > WorldMap;
static WorldMap& worldMap()
{
@@ -349,4 +372,11 @@ void LayoutTestController::evaluateScriptInIsolatedWorld(JSContextRef context, u
JSEvaluateScript(jsContext, script, 0, 0, 0, 0);
}
+void LayoutTestController::setPOSIXLocale(JSStringRef locale)
+{
+ char localeBuf[32];
+ JSStringGetUTF8CString(locale, localeBuf, sizeof(localeBuf));
+ setlocale(LC_ALL, localeBuf);
+}
+
} // namespace WTR
diff --git a/Tools/WebKitTestRunner/InjectedBundle/LayoutTestController.h b/Tools/WebKitTestRunner/InjectedBundle/LayoutTestController.h
index 1f81970..9271124 100644
--- a/Tools/WebKitTestRunner/InjectedBundle/LayoutTestController.h
+++ b/Tools/WebKitTestRunner/InjectedBundle/LayoutTestController.h
@@ -126,6 +126,16 @@ public:
void evaluateScriptInIsolatedWorld(JSContextRef, unsigned worldID, JSStringRef script);
static unsigned worldIDForWorld(WKBundleScriptWorldRef);
+ void showWebInspector();
+ void closeWebInspector();
+ void evaluateInWebInspector(long callId, JSStringRef script);
+ void setTimelineProfilingEnabled(bool);
+
+ void setPOSIXLocale(JSStringRef);
+
+ bool willSendRequestReturnsNull() { return m_willSendRequestReturnsNull; }
+ void setWillSendRequestReturnsNull(bool f) { m_willSendRequestReturnsNull = f; }
+
private:
static const double waitToDumpWatchdogTimerInterval;
@@ -148,6 +158,8 @@ private:
bool m_testRepaint;
bool m_testRepaintSweepHorizontally;
+ bool m_willSendRequestReturnsNull;
+
PlatformTimerRef m_waitToDumpWatchdogTimer;
};
diff --git a/Tools/WebKitTestRunner/InjectedBundle/qt/ActivateFontsQt.cpp b/Tools/WebKitTestRunner/InjectedBundle/qt/ActivateFontsQt.cpp
index d8166d0..9c4bc68 100644
--- a/Tools/WebKitTestRunner/InjectedBundle/qt/ActivateFontsQt.cpp
+++ b/Tools/WebKitTestRunner/InjectedBundle/qt/ActivateFontsQt.cpp
@@ -29,10 +29,13 @@
#include "ActivateFonts.h"
+#include <QApplication>
#include <QByteArray>
#include <QDir>
+#include <QWindowsStyle>
#ifdef Q_WS_X11
+#include <QX11Info>
#include <fontconfig/fontconfig.h>
#endif
@@ -43,6 +46,8 @@ namespace WTR {
void activateFonts()
{
#if defined(Q_WS_X11)
+ FcInit();
+
static int numFonts = -1;
// Some test cases may add or remove application fonts (via @font-face).
@@ -78,6 +83,18 @@ void activateFonts()
appFontSet = FcConfigGetFonts(config, FcSetApplication);
numFonts = appFontSet->nfont;
#endif
+
+ QApplication::setGraphicsSystem("raster");
+ QApplication::setStyle(new QWindowsStyle);
+
+ QFont f("Sans Serif");
+ f.setPointSize(9);
+ f.setWeight(QFont::Normal);
+ f.setStyle(QFont::StyleNormal);
+ QApplication::setFont(f);
+
+ QX11Info::setAppDpiX(0, 96);
+ QX11Info::setAppDpiY(0, 96);
}
}
diff --git a/Tools/WebKitTestRunner/InjectedBundle/qt/InjectedBundle.pro b/Tools/WebKitTestRunner/InjectedBundle/qt/InjectedBundle.pro
index 92d31b8..24db4b8 100644
--- a/Tools/WebKitTestRunner/InjectedBundle/qt/InjectedBundle.pro
+++ b/Tools/WebKitTestRunner/InjectedBundle/qt/InjectedBundle.pro
@@ -43,11 +43,11 @@ HEADERS += \
OBJECTS_DIR = obj/release
}
-include(../../../../WebKit.pri)
+include(../../../../Source/WebKit.pri)
include(../../../../Source/JavaScriptCore/JavaScriptCore.pri)
-addJavaScriptCoreLib(../../../../Source/JavaScriptCore)
+addJavaScriptCoreLib(../../../JavaScriptCore)
include(../../../../Source/WebKit2/WebKit2.pri)
-addWebKit2Lib(../../../../Source/WebKit2)
+addWebKit2Lib(../../../WebKit2)
INCLUDEPATH += \
$$PWD \
@@ -56,6 +56,8 @@ INCLUDEPATH += \
$$PWD/../Bindings \
$$PWD/../../../../Source/JavaScriptCore \
$$PWD/../../../../Source/JavaScriptCore/wtf \
+ $$PWD/../../../../Source/WebCore \
+ $$PWD/../../../../Source/WebCore/platform/text \
$$PWD/../../../../Source/WebKit2 \
$$PWD/../../../../Source/WebKit2/Shared \
$$GENERATED_SOURCES_DIR
diff --git a/Tools/WebKitTestRunner/TestController.cpp b/Tools/WebKitTestRunner/TestController.cpp
index e856176..6f5b9a7 100644
--- a/Tools/WebKitTestRunner/TestController.cpp
+++ b/Tools/WebKitTestRunner/TestController.cpp
@@ -29,9 +29,10 @@
#include "StringFunctions.h"
#include "TestInvocation.h"
#include <cstdio>
-#include <WebKit2/WKPageGroup.h>
#include <WebKit2/WKContextPrivate.h>
+#include <WebKit2/WKPageGroup.h>
#include <WebKit2/WKPreferencesPrivate.h>
+#include <WebKit2/WKRetainPtr.h>
#include <wtf/PassOwnPtr.h>
namespace WTR {
@@ -103,6 +104,13 @@ static bool runBeforeUnloadConfirmPanel(WKPageRef page, WKStringRef message, WKF
return true;
}
+static unsigned long long exceededDatabaseQuota(WKPageRef, WKFrameRef, WKSecurityOriginRef, WKStringRef, WKStringRef, unsigned long long, unsigned long long, unsigned long long, const void*)
+{
+ static const unsigned long long defaultQuota = 5 * 1024 * 1024;
+ return defaultQuota;
+}
+
+
void TestController::runModal(WKPageRef page, const void* clientInfo)
{
runModal(static_cast<PlatformWebView*>(const_cast<void*>(clientInfo)));
@@ -148,7 +156,7 @@ WKPageRef TestController::createOtherPage(WKPageRef oldPage, WKDictionaryRef, WK
runBeforeUnloadConfirmPanel,
0, // didDraw
0, // pageDidScroll
- 0, // exceededDatabaseQuota
+ exceededDatabaseQuota,
0, // runOpenPanel
0, // decidePolicyForGeolocationPermissionRequest
0, // headerHeight
@@ -157,6 +165,7 @@ WKPageRef TestController::createOtherPage(WKPageRef oldPage, WKDictionaryRef, WK
0, // drawFooter
0, // printFrame
runModal,
+ 0, // didCompleteRubberBandForMainFrame
};
WKPageSetPageUIClient(newPage, &otherPageUIClient);
@@ -164,6 +173,18 @@ WKPageRef TestController::createOtherPage(WKPageRef oldPage, WKDictionaryRef, WK
return newPage;
}
+const char* TestController::libraryPathForTesting()
+{
+ // FIXME: This may not be sufficient to prevent interactions/crashes
+ // when running more than one copy of DumpRenderTree.
+ // See https://bugs.webkit.org/show_bug.cgi?id=10906
+ char* dumpRenderTreeTemp = getenv("DUMPRENDERTREE_TEMP");
+ if (dumpRenderTreeTemp)
+ return dumpRenderTreeTemp;
+ return platformLibraryPathForTesting();
+}
+
+
void TestController::initialize(int argc, const char* argv[])
{
platformInitialize();
@@ -219,6 +240,15 @@ void TestController::initialize(int argc, const char* argv[])
m_pageGroup.adopt(WKPageGroupCreateWithIdentifier(pageGroupIdentifier.get()));
m_context.adopt(WKContextCreateWithInjectedBundlePath(injectedBundlePath()));
+
+ const char* path = libraryPathForTesting();
+ if (path) {
+ Vector<char> databaseDirectory(strlen(path) + strlen("/Databases") + 1);
+ sprintf(databaseDirectory.data(), "%s%s", path, "/Databases");
+ WKRetainPtr<WKStringRef> databaseDirectoryWK(AdoptWK, WKStringCreateWithUTF8CString(databaseDirectory.data()));
+ WKContextSetDatabaseDirectory(m_context.get(), databaseDirectoryWK.get());
+ }
+
platformInitializeContext();
WKContextInjectedBundleClient injectedBundleClient = {
@@ -259,7 +289,7 @@ void TestController::initialize(int argc, const char* argv[])
runBeforeUnloadConfirmPanel,
0, // didDraw
0, // pageDidScroll
- 0, // exceededDatabaseQuota
+ exceededDatabaseQuota,
0, // runOpenPanel
0, // decidePolicyForGeolocationPermissionRequest
0, // headerHeight
@@ -268,6 +298,7 @@ void TestController::initialize(int argc, const char* argv[])
0, // drawFooter
0, // printFrame
0, // runModal
+ 0, // didCompleteRubberBandForMainFrame
};
WKPageSetPageUIClient(m_mainWebView->page(), &pageUIClient);
@@ -317,6 +348,8 @@ bool TestController::resetStateToConsistentValues()
WKPreferencesSetXSSAuditorEnabled(preferences, false);
WKPreferencesSetDeveloperExtrasEnabled(preferences, true);
WKPreferencesSetJavaScriptCanOpenWindowsAutomatically(preferences, true);
+ WKPreferencesSetJavaScriptCanAccessClipboard(preferences, true);
+ WKPreferencesSetDOMPasteAllowed(preferences, true);
static WKStringRef standardFontFamily = WKStringCreateWithUTF8CString("Times");
static WKStringRef cursiveFontFamily = WKStringCreateWithUTF8CString("Apple Chancery");
diff --git a/Tools/WebKitTestRunner/TestController.h b/Tools/WebKitTestRunner/TestController.h
index 65305a2..fe37952 100644
--- a/Tools/WebKitTestRunner/TestController.h
+++ b/Tools/WebKitTestRunner/TestController.h
@@ -90,6 +90,9 @@ private:
static void runModal(WKPageRef, const void* clientInfo);
static void runModal(PlatformWebView*);
+ static const char* libraryPathForTesting();
+ static const char* platformLibraryPathForTesting();
+
OwnPtr<TestInvocation> m_currentInvocation;
bool m_dumpPixels;
diff --git a/Tools/WebKitTestRunner/TestInvocation.cpp b/Tools/WebKitTestRunner/TestInvocation.cpp
index 26ecfc0..3af184a 100644
--- a/Tools/WebKitTestRunner/TestInvocation.cpp
+++ b/Tools/WebKitTestRunner/TestInvocation.cpp
@@ -31,6 +31,7 @@
#include <climits>
#include <cstdio>
#include <WebKit2/WKContextPrivate.h>
+#include <WebKit2/WKInspector.h>
#include <WebKit2/WKRetainPtr.h>
#include <wtf/OwnArrayPtr.h>
#include <wtf/PassOwnArrayPtr.h>
@@ -113,6 +114,11 @@ static void sizeWebViewForCurrentTest(char* pathOrURL)
TestController::shared().mainWebView()->resizeTo(normalWidth, normalHeight);
}
+static bool shouldOpenWebInspector(const char* pathOrURL)
+{
+ return strstr(pathOrURL, "inspector/");
+}
+
void TestInvocation::invoke()
{
sizeWebViewForCurrentTest(m_pathOrURL);
@@ -130,17 +136,18 @@ void TestInvocation::invoke()
return;
}
+ if (shouldOpenWebInspector(m_pathOrURL))
+ WKInspectorShow(WKPageGetInspector(TestController::shared().mainWebView()->page()));
+
WKPageLoadURL(TestController::shared().mainWebView()->page(), m_url.get());
TestController::shared().runUntil(m_gotFinalMessage, TestController::LongTimeout);
- if (!m_gotFinalMessage) {
+ if (!m_gotFinalMessage)
dump("Timed out waiting for final message from web process\n");
- return;
- }
- if (m_error) {
+ else if (m_error)
dump("FAIL\n");
- return;
- }
+
+ WKInspectorClose(WKPageGetInspector(TestController::shared().mainWebView()->page()));
}
void TestInvocation::dump(const char* stringToDump)
diff --git a/Tools/WebKitTestRunner/WebKitTestRunner.xcodeproj/project.pbxproj b/Tools/WebKitTestRunner/WebKitTestRunner.xcodeproj/project.pbxproj
index a15fe41..8428403 100644
--- a/Tools/WebKitTestRunner/WebKitTestRunner.xcodeproj/project.pbxproj
+++ b/Tools/WebKitTestRunner/WebKitTestRunner.xcodeproj/project.pbxproj
@@ -32,6 +32,8 @@
6510A78A11EC643800410867 /* WebKitWeightWatcher700.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 6510A77F11EC643800410867 /* WebKitWeightWatcher700.ttf */; };
6510A78B11EC643800410867 /* WebKitWeightWatcher800.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 6510A78011EC643800410867 /* WebKitWeightWatcher800.ttf */; };
6510A78C11EC643800410867 /* WebKitWeightWatcher900.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 6510A78111EC643800410867 /* WebKitWeightWatcher900.ttf */; };
+ 65DD1D9612FFE798004B5285 /* WebCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 65DD1D9512FFE798004B5285 /* WebCore.framework */; };
+ 65DE432512FFE84000171BCA /* WebCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 65DD1D9512FFE798004B5285 /* WebCore.framework */; };
65EB85A011EC67CC0034D300 /* ActivateFonts.mm in Sources */ = {isa = PBXBuildFile; fileRef = 65EB859F11EC67CC0034D300 /* ActivateFonts.mm */; };
BC14E4DB120E02D000826C0C /* GCController.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BC14E4D9120E02D000826C0C /* GCController.cpp */; };
BC14E4EA120E03D800826C0C /* JSGCController.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BC14E4E8120E03D800826C0C /* JSGCController.cpp */; };
@@ -86,6 +88,7 @@
6510A77F11EC643800410867 /* WebKitWeightWatcher700.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; name = WebKitWeightWatcher700.ttf; path = fonts/WebKitWeightWatcher700.ttf; sourceTree = "<group>"; };
6510A78011EC643800410867 /* WebKitWeightWatcher800.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; name = WebKitWeightWatcher800.ttf; path = fonts/WebKitWeightWatcher800.ttf; sourceTree = "<group>"; };
6510A78111EC643800410867 /* WebKitWeightWatcher900.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; name = WebKitWeightWatcher900.ttf; path = fonts/WebKitWeightWatcher900.ttf; sourceTree = "<group>"; };
+ 65DD1D9512FFE798004B5285 /* WebCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = WebCore.framework; sourceTree = BUILT_PRODUCTS_DIR; };
65EB859D11EC67CC0034D300 /* ActivateFonts.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ActivateFonts.h; sourceTree = "<group>"; };
65EB859F11EC67CC0034D300 /* ActivateFonts.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = ActivateFonts.mm; sourceTree = "<group>"; };
8DD76FA10486AA7600D96B5E /* WebKitTestRunner */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = WebKitTestRunner; sourceTree = BUILT_PRODUCTS_DIR; };
@@ -144,6 +147,7 @@
BC7934A511906584005EA8E2 /* Cocoa.framework in Frameworks */,
BC7934AC1190658C005EA8E2 /* WebKit2.framework in Frameworks */,
BCDA2B9A1191051F00C3BC47 /* JavaScriptCore.framework in Frameworks */,
+ 65DD1D9612FFE798004B5285 /* WebCore.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -154,6 +158,7 @@
BC25193E11D15D8B002EBC01 /* Cocoa.framework in Frameworks */,
BC25193F11D15D8B002EBC01 /* WebKit2.framework in Frameworks */,
BC25194011D15D8B002EBC01 /* JavaScriptCore.framework in Frameworks */,
+ 65DE432512FFE84000171BCA /* WebCore.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -195,6 +200,7 @@
BC7934A411906584005EA8E2 /* Cocoa.framework */,
BC7934AB1190658C005EA8E2 /* WebKit2.framework */,
BCDA2B991191051F00C3BC47 /* JavaScriptCore.framework */,
+ 65DD1D9512FFE798004B5285 /* WebCore.framework */,
);
name = "External Frameworks and Libraries";
sourceTree = "<group>";
diff --git a/Tools/WebKitTestRunner/WebKitTestRunnerPrefix.h b/Tools/WebKitTestRunner/WebKitTestRunnerPrefix.h
index 9d508ed..1e540cc 100644
--- a/Tools/WebKitTestRunner/WebKitTestRunnerPrefix.h
+++ b/Tools/WebKitTestRunner/WebKitTestRunnerPrefix.h
@@ -34,4 +34,5 @@
#define min min
#endif
+#include <wtf/Platform.h>
#include <WebKit2/WebKit2.h>
diff --git a/Tools/WebKitTestRunner/mac/TestControllerMac.mm b/Tools/WebKitTestRunner/mac/TestControllerMac.mm
index 8107890..8ceabc1 100644
--- a/Tools/WebKitTestRunner/mac/TestControllerMac.mm
+++ b/Tools/WebKitTestRunner/mac/TestControllerMac.mm
@@ -71,4 +71,9 @@ void TestController::runModal(PlatformWebView* view)
[NSApp runModalForWindow:window];
}
+const char* TestController::platformLibraryPathForTesting()
+{
+ return [[@"~/Library/Application Support/DumpRenderTree" stringByExpandingTildeInPath] UTF8String];
+}
+
} // namespace WTR
diff --git a/Tools/WebKitTestRunner/qt/TestControllerQt.cpp b/Tools/WebKitTestRunner/qt/TestControllerQt.cpp
index df977fb..30a1b5c 100644
--- a/Tools/WebKitTestRunner/qt/TestControllerQt.cpp
+++ b/Tools/WebKitTestRunner/qt/TestControllerQt.cpp
@@ -133,6 +133,11 @@ void TestController::runModal(PlatformWebView*)
// FIXME: Need to implement this to test showModalDialog.
}
+const char* TestController::platformLibraryPathForTesting()
+{
+ return 0;
+}
+
#include "TestControllerQt.moc"
} // namespace WTR
diff --git a/Tools/WebKitTestRunner/qt/WebKitTestRunner.pro b/Tools/WebKitTestRunner/qt/WebKitTestRunner.pro
index 73ab4b0..de648ea 100644
--- a/Tools/WebKitTestRunner/qt/WebKitTestRunner.pro
+++ b/Tools/WebKitTestRunner/qt/WebKitTestRunner.pro
@@ -6,7 +6,7 @@ isEmpty(OUTPUT_DIR): OUTPUT_DIR = ../../..
GENERATED_SOURCES_DIR = ../generated
-include(../../../WebKit.pri)
+include(../../../Source/WebKit.pri)
!CONFIG(release, debug|release) {
OBJECTS_DIR = obj/debug
@@ -68,4 +68,4 @@ linux-* {
}
include(../../../Source/JavaScriptCore/JavaScriptCore.pri)
-addJavaScriptCoreLib(../../../Source/JavaScriptCore)
+addJavaScriptCoreLib(../../JavaScriptCore)
diff --git a/Tools/WebKitTestRunner/win/TestControllerWin.cpp b/Tools/WebKitTestRunner/win/TestControllerWin.cpp
index 08f188f..5af5503 100644
--- a/Tools/WebKitTestRunner/win/TestControllerWin.cpp
+++ b/Tools/WebKitTestRunner/win/TestControllerWin.cpp
@@ -157,4 +157,9 @@ void TestController::runModal(PlatformWebView*)
// FIXME: Need to implement this to test showModalDialog.
}
+const char* TestController::platformLibraryPathForTesting()
+{
+ return 0;
+}
+
} // namespace WTR
diff --git a/Tools/wx/browser/wscript b/Tools/wx/browser/wscript
index 4fb00b4..7c5aeee 100644
--- a/Tools/wx/browser/wscript
+++ b/Tools/wx/browser/wscript
@@ -30,7 +30,7 @@ import sys
from settings import *
include_paths = [os.path.join(wk_root, 'Source', 'WebCore', 'bindings', 'wx'),
- os.path.join(wk_root, 'WebKit', 'wx')]
+ os.path.join(wk_root, 'Source', 'WebKit', 'wx')]
def set_options(opt):
common_set_options(opt)
diff --git a/Tools/wx/build/build_utils.py b/Tools/wx/build/build_utils.py
index bf440a6..569703d 100644
--- a/Tools/wx/build/build_utils.py
+++ b/Tools/wx/build/build_utils.py
@@ -120,7 +120,7 @@ def update_wx_deps(conf, wk_root, msvc_version='msvc2008'):
sys.exit(1)
# since this module is still experimental
- wxpy_dir = os.path.join(wk_root, 'WebKit', 'wx', 'bindings', 'python')
+ wxpy_dir = os.path.join(wk_root, 'Source', 'WebKit', 'wx', 'bindings', 'python')
swig_module = download_if_newer('http://wxwebkit.wxcommunity.com/downloads/deps/swig.py.txt', wxpy_dir)
if swig_module:
shutil.copy(os.path.join(wxpy_dir, 'swig.py.txt'), os.path.join(wxpy_dir, 'swig.py'))
diff --git a/Tools/wx/build/settings.py b/Tools/wx/build/settings.py
index 64c2693..2b757c4 100644
--- a/Tools/wx/build/settings.py
+++ b/Tools/wx/build/settings.py
@@ -86,7 +86,6 @@ jscore_dirs = [
'interpreter',
'jit',
'parser',
- 'pcre',
'profiler',
'runtime',
'wtf',
@@ -102,7 +101,6 @@ webcore_dirs = [
'Source/WebCore/bindings/cpp',
'Source/WebCore/bindings/generic',
'Source/WebCore/bindings/js',
- 'Source/WebCore/bindings/js/specialization',
'Source/WebCore/bridge',
'Source/WebCore/bridge/c',
'Source/WebCore/bridge/jsc',
@@ -116,6 +114,7 @@ webcore_dirs = [
'Source/WebCore/html',
'Source/WebCore/html/canvas',
'Source/WebCore/html/parser',
+ 'Source/WebCore/html/shadow',
'Source/WebCore/inspector',
'Source/WebCore/loader',
'Source/WebCore/loader/appcache',