diff options
author | Iain Merrick <husky@google.com> | 2010-08-19 17:55:56 +0100 |
---|---|---|
committer | Iain Merrick <husky@google.com> | 2010-08-23 11:05:40 +0100 |
commit | f486d19d62f1bc33246748b14b14a9dfa617b57f (patch) | |
tree | 195485454c93125455a30e553a73981c3816144d /WebKitTools | |
parent | 6ba0b43722d16bc295606bec39f396f596e4fef1 (diff) | |
download | external_webkit-f486d19d62f1bc33246748b14b14a9dfa617b57f.zip external_webkit-f486d19d62f1bc33246748b14b14a9dfa617b57f.tar.gz external_webkit-f486d19d62f1bc33246748b14b14a9dfa617b57f.tar.bz2 |
Merge WebKit at r65615 : Initial merge by git.
Change-Id: Ifbf384f4531e3b58475a662e38195c2d9152ae79
Diffstat (limited to 'WebKitTools')
98 files changed, 3623 insertions, 912 deletions
diff --git a/WebKitTools/BuildSlaveSupport/build.webkit.org-config/config.json b/WebKitTools/BuildSlaveSupport/build.webkit.org-config/config.json index eda05f1..49d770d 100644 --- a/WebKitTools/BuildSlaveSupport/build.webkit.org-config/config.json +++ b/WebKitTools/BuildSlaveSupport/build.webkit.org-config/config.json @@ -8,6 +8,7 @@ { "name": "apple-xserve-4", "platform": "mac-snowleopard" }, { "name": "apple-xserve-5", "platform": "mac-snowleopard" }, { "name": "apple-xserve-6", "platform": "mac-snowleopard" }, + { "name": "apple-xserve-7", "platform": "mac-snowleopard" }, { "name": "apple-pixel-1", "platform": "mac-leopard" }, @@ -66,7 +67,7 @@ }, { "name": "SnowLeopard Intel Release (Build)", "type": "Build", "builddir": "snowleopard-intel-release", "platform": "mac-snowleopard", "configuration": "release", "architectures": ["x86_64"], - "triggers": ["snowleopard-intel-release-tests"], + "triggers": ["snowleopard-intel-release-tests", "snowleopard-intel-release-tests-wk2"], "slavenames": ["apple-xserve-4", "test-slave"] }, { "name": "SnowLeopard Intel Release (Tests)", "type": "Test", "builddir": "snowleopard-intel-release-tests", @@ -77,6 +78,10 @@ "platform": "mac-snowleopard", "configuration": "debug", "architectures": ["x86_64"], "slavenames": ["apple-macpro-1", "apple-macpro-3", "test-slave"] }, + { "name": "SnowLeopard Intel Release (WebKit2 Tests)", "type": "TestWebKit2", "builddir": "snowleopard-intel-release-tests-wk2", + "platform": "mac-snowleopard", "configuration": "release", "architectures": ["x86_64"], + "slavenames": ["apple-xserve-7", "test-slave"] + }, { "name": "Windows Release (Build)", "type": "Build", "builddir": "win-release", "platform": "win", "configuration": "release", "architectures": ["i386"], @@ -205,6 +210,9 @@ { "type": "Triggerable", "name": "snowleopard-intel-release-tests", "builderNames": ["SnowLeopard Intel Release (Tests)"] }, + { "type": "Triggerable", "name": "snowleopard-intel-release-tests-wk2", + "builderNames": ["SnowLeopard Intel Release (WebKit2 Tests)"] + }, { "type": "Triggerable", "name": "win-release-tests", "builderNames": ["Windows Release (Tests)"] }, diff --git a/WebKitTools/BuildSlaveSupport/build.webkit.org-config/master.cfg b/WebKitTools/BuildSlaveSupport/build.webkit.org-config/master.cfg index 5ff4681..acedbd2 100644 --- a/WebKitTools/BuildSlaveSupport/build.webkit.org-config/master.cfg +++ b/WebKitTools/BuildSlaveSupport/build.webkit.org-config/master.cfg @@ -247,6 +247,9 @@ class RunWebKitTests(shell.Test): class NewRunWebKitTests(RunWebKitTests): command = ["python", "./WebKitTools/Scripts/new-run-webkit-tests", "--noshow-results", "--verbose", "--results-directory", "layout-test-results", + "--builder-name", WithProperties("%(buildername)s"), + "--build-number", WithProperties("%(buildnumber)s"), + "--test-results-server", "test-results.appspot.com", WithProperties("--%(configuration)s"), "--use-drt"] @@ -306,6 +309,12 @@ class RunWebKitLeakTests(RunWebKitTests): return RunWebKitTests.start(self) +class RunWebKit2Tests(RunWebKitTests): + def start(self): + self.setCommand(self.command + ["--webkit-test-runner"]) + return RunWebKitTests.start(self) + + class ArchiveTestResults(shell.ShellCommand): command = ["python", "./WebKitTools/BuildSlaveSupport/test-result-archive", WithProperties("--platform=%(platform)s"), WithProperties("--%(configuration)s"), "archive"] @@ -405,6 +414,8 @@ class BuildAndTestLeaksFactory(BuildAndTestFactory): class NewBuildAndTestFactory(BuildAndTestFactory): TestClass = NewRunWebKitTests +class TestWebKit2Factory(TestFactory): + TestClass = RunWebKit2Tests def loadBuilderConfig(c): # FIXME: These file handles are leaked. diff --git a/WebKitTools/ChangeLog b/WebKitTools/ChangeLog index e911169..324c32d 100644 --- a/WebKitTools/ChangeLog +++ b/WebKitTools/ChangeLog @@ -1,3 +1,875 @@ +2010-08-18 Adam Roben <aroben@apple.com> + + Fix hang when saving crash logs on Windows + + * Scripts/old-run-webkit-tests: + (setUpWindowsCrashLogSaving): + (END): + Pass -s to regtool so it will write the Auto value as a string instead + of as a number. This was causing a "do you want to debug?" dialog to + appear. + +2010-08-17 Victor Wang <victorw@chromium.org> + + Unreviewed. Fixed chromium incremental test json upload. + Quote builder name and test results server in url. + + * Scripts/webkitpy/layout_tests/layout_package/json_results_generator.py: + +2010-08-17 Laszlo Gombos <laszlo.1.gombos@nokia.com> + + Reviewed by Ariya Hidayat. + + [Qt] [Symbian] Consistently use Q_OS_SYMBIAN to guard all Symbian platform dependencies + https://bugs.webkit.org/show_bug.cgi?id=44124 + + Q_WS_S60 is not defined for Symbian^4 devices as Q_WS_S60 used to guard + Avkon UI framework dependencies. Use Q_OS_SYMBIAN everywhere to mark + Symbian dependencies. + + * DumpRenderTree/qt/DumpRenderTreeQt.cpp: + (WebCore::DumpRenderTree::open): + * QtTestBrowser/launcherwindow.cpp: + (LauncherWindow::init): + (LauncherWindow::toggleFullScreenMode): + (LauncherWindow::showFPS): + (LauncherWindow::updateFPS): + * QtTestBrowser/launcherwindow.h: + (WindowOptions::WindowOptions): + * QtTestBrowser/mainwindow.cpp: + (MainWindow::buildUI): + +2010-08-17 Dirk Pranke <dpranke@chromium.org> + + Reviewed by David Levin. + + new-run-webkit-tests: remove --show-sources option + + --show-sources is pretty much obsolete with --trace everything, so + I'm removing it. + + Also rename a couple of methods in the TestTextDiff class to make their + intended visibility (private) more obvious. + + https://bugs.webkit.org/show_bug.cgi?id=44143 + + * Scripts/webkitpy/layout_tests/layout_package/printing.py: + * Scripts/webkitpy/layout_tests/run_webkit_tests.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: + +2010-08-17 Dirk Pranke <dpranke@chromium.org> + + Reviewed by David Levin. + + remove --fuzzy-image-diff in new-run-webkit-tests (it doesn't work) + + This code bit-rotted at some point more than a year ago, and nobody seems + to miss it. old-run-webkit-tests has a --tolerance flag that new-run-webkit-tests + should support instead, making this flag unnecessary anyway. + + https://bugs.webkit.org/show_bug.cgi?id=44141 + + * Scripts/webkitpy/layout_tests/layout_package/test_failures.py: + * Scripts/webkitpy/layout_tests/run_webkit_tests.py: + * Scripts/webkitpy/layout_tests/test_types/fuzzy_image_diff.py: Removed. + +2010-08-17 Victor Wang <victorw@chromium.org> + + Reviewed by Ojan Vafai. + + Update json results generator to have incremental json including + results for tests that pass in current run but failed before. + + https://bugs.webkit.org/show_bug.cgi?id=44119 + + * 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/run_webkit_tests.py: + +2010-08-17 Dirk Pranke <dpranke@chromium.org> + + Reviewed by Eric Seidel. + + fix test-webkitpy, add easy way to find a checkout root + + test-webkitpy currently doesn't work right if run from someplace other + than the checkout root, and it spews a bunch of debug logging because + the deduplicate_tests tests contaminates the test environment. + + This patch cleans up the deduplicate_tests unit tests, and creates + two new methods in scm.py: find_checkout_root() and default_scm(), + both of which use a single algorithm for guessing what checkout root + to use if you aren't explicitly told one from a path. + + https://bugs.webkit.org/show_bug.cgi?id=44001 + + * Scripts/deduplicate-tests: + * Scripts/webkitpy/common/checkout/scm.py: + * Scripts/webkitpy/common/checkout/scm_unittest.py: + * Scripts/webkitpy/layout_tests/deduplicate_tests.py: + * Scripts/webkitpy/layout_tests/deduplicate_tests_unittest.py: + * Scripts/webkitpy/layout_tests/port/test.py: + * Scripts/webkitpy/layout_tests/rebaseline_chromium_webkit_tests.py: + * Scripts/webkitpy/layout_tests/rebaseline_chromium_webkit_tests_unittest.py: + * Scripts/webkitpy/tool/main.py: + +2010-08-17 Victor Wang <victorw@chromium.org> + + Reviewed by Ojan Vafai. + + Add support to the test results server for downloading json that + contains test list only. + + This is for json results generator to generate incremental json + results so that it includes results not only for tests failed in + current run, but also tests failed before. + + Also set the results type to "N" (no data) instead of "P" (pass) + if test results cannot be found in incremental json file. + + https://bugs.webkit.org/show_bug.cgi?id=44117 + + * TestResultServer/handlers/testfilehandler.py: + * TestResultServer/model/jsonresults.py: + * TestResultServer/model/jsonresults_unittest.py: + +2010-08-17 Adam Roben <aroben@apple.com> + + Use the right path style + + * Scripts/old-run-webkit-tests: + +2010-08-17 Adam Roben <aroben@apple.com> + + Fix typo + + * Scripts/old-run-webkit-tests: + +2010-08-17 Adam Roben <aroben@apple.com> + + Don't hang when running run-webkit-tests as a non-Administrator on + Vista/7 + + * Scripts/old-run-webkit-tests: + (setUpWindowsCrashLogSaving): Use regtool to set NTSD as the + post-mortem debugger, rather than using NTSD itself. The latter waits + for user input when it fails to set the registry values; the former + does not. + +2010-08-17 Adam Roben <aroben@apple.com> + + Teach run-webkit-tests, DumpRenderTree, and WebKitTestRunner how to + save crash logs on Windows + + The crash logs are saved to /tmp/layout-test-results and have names + like CrashLog_02bc_2010-08-17_14-36-20-108.txt. + + Unfortunately, crashes in the WebKit2 web process are recorded as + time-outs by run-webkit-tests. Fixing this is covered by + <http://webkit.org/b/44121>. + + Fixes <http://webkit.org/b/37859> <rdar://problem/7883560> + DumpRenderTree should save a stack trace and/or dump file when it + crashes + + Reviewed by Sam Weinig. + + * DumpRenderTree/win/DumpRenderTree.cpp: + (exceptionFilter): + (main): + * WebKitTestRunner/win/TestControllerWin.cpp: + (WTR::exceptionFilter): + (WTR::TestController::platformInitialize): + These changes set up an exception filter that prints #CRASHED to + stderr, then lets the exception propagate normally. This allows + run-webkit-tests to detect when we've crashed even when a post-mortem + debugger attaches to the process. + + * Scripts/old-run-webkit-tests: + (top level): Declared some variables used by the crash-log-saving + code. + (openDumpTool): Copy _NT_SYMBOL_PATH into the clean environment so + that the post-mortem debugger has access to it. + (toCygwinPath): Added. This is the opposite of toWindowsPath. + (readFromDumpToolWithTimer): If the dump tool prints #CRASHED to + stderr, consider it a crash. + (setUpWindowsCrashLogSaving): Added. Saves the current post-mortem + debugger, then sets ntsd as the post-mortem debugger. ntsd is + configured to save a crash log and then quit automatically. + (END): Added. Restores the previous post-mortem debugger when the + script exits. + +2010-08-17 Victor Wang <victorw@chromium.org> + + Reviewed by ojan@chromium.org. + + Update test results server: + 1. Normalize test results and times after merging (prune tests where + all runs pass or do not have data, truncate all test items to max + number of builds) + 2. times should be int not string. + 3. when inserting a new test item, should keep old data regardless + whether or not they have same item type with new one. + + https://bugs.webkit.org/show_bug.cgi?id=43861 + + * TestResultServer/model/jsonresults.py: + * TestResultServer/model/jsonresults_unittest.py: + +2010-08-16 Sam Weinig <sam@webkit.org> + + Reviewed by Mark Rowe. + + Add WebKit2 Mac tester to buildbot. + + * BuildSlaveSupport/build.webkit.org-config/config.json: + * BuildSlaveSupport/build.webkit.org-config/master.cfg: + +2010-08-16 Paul Sawaya <psawaya@apple.com> + + Reviewed by Chris Marrin. + + Added shader validation via ANGLE + https://bugs.webkit.org/show_bug.cgi?id=42405 + + Added ANGLE to webkit build + + * Scripts/build-webkit: + +2010-08-16 Kevin Ollivier <kevino@theolliviers.com> + + [wx] Build fix, do not build WebCore as a convenience library as this leads to + errors in the Win build w/export symbols and causes problems with DOM bindings + debugging in gdb. + + * DumpRenderTree/wscript: + * Scripts/build-webkit: + * wx/browser/wscript: + * wx/build/settings.py: + * wx/build/waf_extensions.py: + +2010-08-16 Dan Bernstein <mitz@apple.com> + + Build fix. + + * WebKitTestRunner/TestController.cpp: + (WTR::createOtherPage): Initialize the contentsSizeChanged member. + (WTR::TestController::initialize): Ditto. + +2010-08-16 Balazs Kelemen <kb@inf.u-szeged.hu> + + Reviewed by Kenneth Rohde Christiansen. + + Handle content size change in WebKit2 + Re-landing after fix. + + https://bugs.webkit.org/show_bug.cgi?id=43198 + + * MiniBrowser/mac/BrowserWindowController.m: + (-[BrowserWindowController awakeFromNib]): Initialize WKPageUICallback::contetsSizeChanged to 0. + * MiniBrowser/win/BrowserView.cpp: + (BrowserView::create): Initialize WKPageUICallback::contetsSizeChanged to 0. + +2010-08-16 Sheriff Bot <webkit.review.bot@gmail.com> + + Unreviewed, rolling out r65419. + http://trac.webkit.org/changeset/65419 + https://bugs.webkit.org/show_bug.cgi?id=44053 + + Broke the Windows build (Requested by bbandix on #webkit). + + * MiniBrowser/mac/BrowserWindowController.m: + (-[BrowserWindowController awakeFromNib]): + * MiniBrowser/win/BrowserView.cpp: + (BrowserView::create): + +2010-08-16 Balazs Kelemen <kb@inf.u-szeged.hu> + + Reviewed by Kenneth Rohde Christiansen. + + Handle content size change in WebKit2 + + https://bugs.webkit.org/show_bug.cgi?id=43198 + + * MiniBrowser/mac/BrowserWindowController.m: + (-[BrowserWindowController awakeFromNib]): Initialize WKPageUICallback::contetsSizeChanged to 0. + * MiniBrowser/win/BrowserView.cpp: + (BrowserView::create): Initialize WKPageUICallback::contetsSizeChanged to 0. + +2010-08-16 Ariya Hidayat <ariya@sencha.com> + + Add my new email address to committers.py. + + * Scripts/webkitpy/common/config/committers.py: + +2010-08-16 Zoltan Horvath <zoltan@webkit.org> + + Add my old e-mail addresses to committers.py. + + * Scripts/webkitpy/common/config/committers.py: + +2010-08-15 Jon Honeycutt <jhoneycutt@apple.com> + + WebEditorClient::didBeginEditing is never called in WebKit2 + https://bugs.webkit.org/show_bug.cgi?id=42939 + + Reviewed by Sam Weinig. + + * WebKitTestRunner/PlatformWebView.h: + Declare focus(). + + * WebKitTestRunner/TestController.cpp: + (WTR::TestController::resetStateToConsistentValues): + Focus the PlatformWebView. + + * WebKitTestRunner/mac/PlatformWebViewMac.mm: + (WTR::PlatformWebView::focus): + Stubbed. + + * WebKitTestRunner/win/PlatformWebViewWin.cpp: + (WTR::PlatformWebView::focus): + Focus the view. + +2010-08-15 Jon Honeycutt <jhoneycutt@apple.com> + + run-webkit-tests should not strip editing callbacks when using + WebKitTestRunner on Windows + https://bugs.webkit.org/show_bug.cgi?id=44000 + + Reviewed by Mark Rowe. + + * Scripts/old-run-webkit-tests: + Leave $stripEditingCallbacks undefined until we look for command-line + arguments. If using WebKit2, set it to 0 if not explicity set on the + command line. Later, set it to isCygwin() to match old behavior if it is + not yet defined. + +2010-08-15 Kevin Ollivier <kevino@theolliviers.com> + + [wx] Build fix, remove define always set to the correct value by wtf/Platform.h. + + * wx/build/settings.py: + +2010-08-14 Martin Robinson <mrobinson@igalia.com> + + Reviewed by Kenneth Rohde Christiansen. + + [GTK] autogen.sh not executed if build-webkit options change + https://bugs.webkit.org/show_bug.cgi?id=42266 + + Rerun autogen.sh in situations where the arguments to build-webkit have + changed since the previous build. This will fix some issues on the bots + where the build does not notice changes to default build-webkit arguments. + + * Scripts/webkitdirs.pm: Add special logic for detecting changes to build-webkit arguments. + +2010-08-14 Eric Seidel <eric@webkit.org> + + Unreviewed. Another fix to support python 2.3. + + Add support for MathML entities + https://bugs.webkit.org/show_bug.cgi?id=43949 + + * Scripts/webkitpy/thirdparty/simplejson/decoder.py: + - It looks like our simplejson is version 1.7.3 which + should be python 2.3 compatible. But someone modified + our copy slightly from the original source. + I've removed the relative import in hopes this fixes + the problem. + +2010-08-13 Eric Seidel <eric@webkit.org> + + Unreviewed. Build fix only. + + Add support for MathML entities + https://bugs.webkit.org/show_bug.cgi?id=43949 + + * Scripts/create-html-entity-table: + - Hack sys.path to avoid executing 2.5 dependent python + on systems (like chromium-win and Tiger) which do not have 2.5 python. + +2010-08-13 Adam Barth <abarth@webkit.org> + + Reviewed by Eric Seidel. + + Rename some concepts in HTML entity search to be more self-documenting + https://bugs.webkit.org/show_bug.cgi?id=44004 + + Reflect name change in generator script. + + * Scripts/create-html-entity-table: + +2010-08-12 Adam Barth <abarth@webkit.org> + + Reviewed by Eric Seidel. + + Add support for MathML entities + https://bugs.webkit.org/show_bug.cgi?id=43949 + + A script for generating the C++ state data structure describing all the + entities from a JSON description. + + * Scripts/create-html-entity-table: Added. + +2010-08-13 Dirk Pranke <dpranke@chromium.org> + + Reviewed by Eric Seidel. + + Rewrite new-run-webkit-test's wait_for_threads_to_finish loop to + check for exceptions on all threads, not just the first thread. + + This change also changes the logging behavior for wedged threads + to only dump the stacks of threads that are actually wedged. + + Refactor the thread classes in the dump_render_tree_thread module + to make the contract between TestRunner and TestShellThread clearer. + + Added a bunch of unit tests. + https://bugs.webkit.org/show_bug.cgi?id=38561 + + * Scripts/webkitpy/layout_tests/layout_package/dump_render_tree_thread.py: + * Scripts/webkitpy/layout_tests/run_webkit_tests.py: + * Scripts/webkitpy/layout_tests/run_webkit_tests_unittest.py: + +2010-08-13 Kenichi Ishibashi <bashi@google.com> + + Reviewed by Shinichiro Hamaji. + + Add test_expectations.txt syntax checker to check-webkit-style. + https://bugs.webkit.org/show_bug.cgi?id=43899 + + Just utilizing layout_tests/layout_package/test_expectations.py for checking + the syntax of test_expectations.txt. + This change also moves tab checking class from style/checkers/text.py to + style/checkers/common.py for sharing code. + + * Scripts/webkitpy/layout_tests/layout_package/test_expectations.py: + * Scripts/webkitpy/style/checker.py: + * Scripts/webkitpy/style/checkers/common.py: + * Scripts/webkitpy/style/checkers/common_unittest.py: + * Scripts/webkitpy/style/checkers/test_expectations.py: Added. + * Scripts/webkitpy/style/checkers/test_expectations_unittest.py: Added. + * Scripts/webkitpy/style/checkers/text.py: + * Scripts/webkitpy/style_references.py: + +2010-08-12 Jon Honeycutt <jhoneycutt@apple.com> + + WebKitTestRunner does not correctly resize WebView for W3C SVG tests + https://bugs.webkit.org/show_bug.cgi?id=43945 + + Reviewed by Sam Weinig. + + * WebKitTestRunner/TestInvocation.cpp: + (WTR::sizeWebViewForCurrentTest): + Allow for a Windows-style path. + + * WebKitTestRunner/win/PlatformWebViewWin.cpp: + (WTR::PlatformWebView::resizeTo): + Call SetWindowPos to resize the view window. + +2010-08-12 David Levin <levin@chromium.org> + + Build break fix. + + * WebKitTestRunner/TestController.cpp: + (WTR::TestController::resetStateToConsistentValues): Removed usage + of a variable that doesn't exist in the class. + +2010-08-12 Jon Honeycutt <jhoneycutt@apple.com> + + WebKitTestRunner needs to run tests without using native controls + https://bugs.webkit.org/show_bug.cgi?id=43772 + + Reviewed by Sam Weinig. + + * WebKitTestRunner/TestController.cpp: + (WTR::TestController::initialize): + Call platformInitializeContext(). + + * WebKitTestRunner/TestController.h: + Declare platformInitializeContext(). + + * WebKitTestRunner/mac/TestControllerMac.mm: + (WTR::TestController::platformInitializeContext): + Stubbed. + + * WebKitTestRunner/win/TestControllerWin.cpp: + (WTR::TestController::platformInitializeContext): + Call WKContextSetShouldPaintNativeControls() to disable native control + drawing. + +2010-08-12 Sam Weinig <sam@webkit.org> + + Reviewed by Alexey Proskuryakov. + + WebKitTestRunner should be more aggressive about ensuring consistent state between tests + https://bugs.webkit.org/show_bug.cgi?id=43653 + + * WebKitTestRunner/InjectedBundle/InjectedBundle.cpp: + (WTR::InjectedBundle::InjectedBundle): + (WTR::InjectedBundle::didReceiveMessage): + (WTR::InjectedBundle::beginTesting): + (WTR::InjectedBundle::done): + * WebKitTestRunner/InjectedBundle/InjectedBundle.h: + (WTR::InjectedBundle::isTestRunning): + (WTR::InjectedBundle::): + * WebKitTestRunner/InjectedBundle/InjectedBundlePage.cpp: + (WTR::InjectedBundlePage::stopLoading): + (WTR::InjectedBundlePage::didStartProvisionalLoadForFrame): + (WTR::InjectedBundlePage::dump): + (WTR::InjectedBundlePage::didFinishLoadForFrame): + (WTR::InjectedBundlePage::didFailLoadWithErrorForFrame): + (WTR::InjectedBundlePage::didReceiveTitleForFrame): + (WTR::InjectedBundlePage::didClearWindowForFrame): + (WTR::InjectedBundlePage::didFinishDocumentLoadForFrame): + (WTR::InjectedBundlePage::willAddMessageToConsole): + (WTR::InjectedBundlePage::willSetStatusbarText): + (WTR::InjectedBundlePage::willRunJavaScriptAlert): + (WTR::InjectedBundlePage::willRunJavaScriptConfirm): + (WTR::InjectedBundlePage::shouldBeginEditing): + (WTR::InjectedBundlePage::shouldEndEditing): + (WTR::InjectedBundlePage::shouldInsertNode): + (WTR::InjectedBundlePage::shouldInsertText): + (WTR::InjectedBundlePage::shouldDeleteRange): + (WTR::InjectedBundlePage::shouldChangeSelectedRange): + (WTR::InjectedBundlePage::shouldApplyStyle): + (WTR::InjectedBundlePage::didBeginEditing): + (WTR::InjectedBundlePage::didEndEditing): + (WTR::InjectedBundlePage::didChange): + (WTR::InjectedBundlePage::didChangeSelection): + Don't do any work if we are not currently running a test. + + * WebKitTestRunner/InjectedBundle/InjectedBundlePage.h: + * WebKitTestRunner/StringFunctions.h: + (WTR::toCF): + Add conversion function for WKURLRef -> CFURLRef + + * WebKitTestRunner/TestController.cpp: + (WTR::TestController::TestController): + (WTR::TestController::initialize): + (WTR::TestController::resetStateToConsistentValues): + (WTR::TestController::runTest): + (WTR::TestController::didFinishLoadForFrame): + * WebKitTestRunner/TestController.h: + (WTR::TestController::): + * WebKitTestRunner/TestInvocation.cpp: + (WTR::TestInvocation::invoke): + * WebKitTestRunner/TestInvocation.h: + Move resetting code to TestController. + + * WebKitTestRunner/WebKitTestRunner.xcodeproj/project.pbxproj: + * WebKitTestRunner/mac/TestControllerMac.mm: + (WTR::TestController::runUntil): + * WebKitTestRunner/mac/TestInvocationMac.mm: Removed. + * WebKitTestRunner/win/TestControllerWin.cpp: + (WTR::TestController::runUntil): + * WebKitTestRunner/win/TestInvocationWin.cpp: Removed. + * WebKitTestRunner/win/WebKitTestRunner.vcproj: + Move runUntil to TestController. + +2010-08-12 Lucas De Marchi <lucas.demarchi@profusion.mobi> + + Unreviewed. + + Adding myself to the committers list. + + * Scripts/webkitpy/common/config/committers.py: + +2010-08-12 Hayato Ito <hayato@chromium.org> + + Reviewed by Tony Chang. + + Merge pretty printers for gdb. + https://bugs.webkit.org/show_bug.cgi?id=43850 + + We need to update webcore.py because basic string classes have moved to WTF from WebCore. + It is good timing to merge webcore.py and wtf.py and name it 'webkit.py'. + webcore.py is left for backward compatibility. + + * gdb/webcore.py: + * gdb/webkit.py: Added. + * gdb/wtf.py: Removed. + +2010-08-11 Tony Chang <tony@chromium.org> + + Reviewed by David Levin. + + [chromium] add google-chrome layout test result directories + https://bugs.webkit.org/show_bug.cgi?id=43889 + + * Scripts/webkitpy/layout_tests/port/chromium_win.py: + * Scripts/webkitpy/layout_tests/port/factory.py: + * Scripts/webkitpy/layout_tests/port/google_chrome.py: Added. + * Scripts/webkitpy/layout_tests/test_types/image_diff.py: + +2010-08-11 Kent Tamura <tkent@chromium.org> + + Reviewed by Dimitri Glazkov. + + [DRT/Chromium] Disable accelerated compositing + https://bugs.webkit.org/show_bug.cgi?id=43894 + + Disable accelerated compositing because DRT is not ready for + it. This change fixes hundreds of test crashes on Windows and + Linux. + + * DumpRenderTree/chromium/TestShell.cpp: + (TestShell::resetWebSettings): + +2010-08-11 Gustavo Noronha Silva <gustavo.noronha@collabora.co.uk> + + Unreviewed. Adding my Collabora personality to the list. + + * Scripts/webkitpy/common/config/committers.py: + +2010-08-11 Martin Robinson <mrobinson@igalia.com> + + Adding myself as a reviewer. + + * Scripts/webkitpy/common/config/committers.py: + +2010-08-11 Daniel Bates <dbates@rim.com> + + Reviewed by Darin Adler. + + Perl warnings when running commit-log-editor + https://bugs.webkit.org/show_bug.cgi?id=43856 + + Fixes Perl warnings introduced by the patch for Bug #40548. + + Perl doesn't have symbolic names for True/False. Instead, we + should use boolean values. Moreover, the variable installedEditorApplication + is not be used and should be renamed builtEditorApplication so that it + uses the existing machinery to set the commit log editor application. + + * Scripts/commit-log-editor: + +2010-08-11 Adam Barth <abarth@webkit.org> + + Reviewed by Eric Seidel. + + Trying waiting for httpd lock in the EWS + https://bugs.webkit.org/show_bug.cgi?id=43833 + + If this works, we can probably run the tests on the mac-ews, which + would be very exciting. :) + + * Scripts/webkitpy/tool/steps/runtests.py: + +2010-08-11 Marcus Bulach <bulach@chromium.org> + + Reviewed by Eric Seidel. + + Check in a script to list redundant test outputs. + https://bugs.webkit.org/show_bug.cgi?id=37630 + + If e.g. platform/mac-leopard is missing an expected test output, we + fall back on platform/mac. This means it's possible to grow redundant + test outputs, where we have the same expected data in both a platform + directory and another platform it falls back on. + (original patch by Evan Marting <evan@chromium.org> https://bugs.webkit.org/attachment.cgi?id=53398) + + * Scripts/deduplicate-tests: Added. + * Scripts/webkitpy/layout_tests/deduplicate_tests.py: Added. + * Scripts/webkitpy/layout_tests/deduplicate_tests_unittest.py: Added. + +2010-08-11 Antonio Gomes <tonikitoo@webkit.org> + + Reviewed by Ariya Hidayat. + + [Qt] QtTestBrowser: after switching between QWebView and QGraphicsWebView, rotation actions get broken + https://bugs.webkit.org/show_bug.cgi?id=43853 + + LauncherWindow::createChrome is connecting menu itens to WebViewGraphicsBased's slots directly. + It behaviors badly when user launches the QtTestBrowser in QWebView mode, since then switching to + QGraphicsWebView mode, createChrome is not called again, and menu items end up not getting connected + to slots at all. + + * QtTestBrowser/launcherwindow.cpp: + (LauncherWindow::createChrome): + (LauncherWindow::animatedFlip): + (LauncherWindow::animatedYFlip): + * QtTestBrowser/launcherwindow.h: + +2010-08-11 Antonio Gomes <tonikitoo@webkit.org> + + Reviewed by Simon Hausmann. + + [Qt] QtTestBrowser: switching between QWebView and QGraphicsWebView modes is broken + https://bugs.webkit.org/show_bug.cgi?id=43851 + + All window options data (including the bool holding if the view is either QWebView or + QGraphicsWebView based) is stored in m_windowOptions, a class member of LauncherWindow. + When toggle the view from QWebView to QGraphicsWebView based (and vice-versa), we were + not updating LauncherWindow::WindowOptions::m_useGraphicsView bit, and then things were + getting broken. + + Patch addresses this issue. + + * QtTestBrowser/launcherwindow.cpp: + (LauncherWindow::createChrome): + (LauncherWindow::toggleWebView): + (LauncherWindow::toggleAcceleratedCompositing): + +2010-08-10 Antonio Gomes <tonikitoo@webkit.org> + + Reviewed by Ariya Hidayat. + + [Qt] QtTestBrowser: lazy instantiate "YRotation" state machine and related objects + https://bugs.webkit.org/show_bug.cgi?id=43831 + + Only instantiate QStateMachine and friends associated to the YRotation action on demand. + + * QtTestBrowser/webview.cpp: + (WebViewGraphicsBased::WebViewGraphicsBased): + (WebViewGraphicsBased::animatedYFlip): + +2010-08-11 Darin Adler <darin@apple.com> + + Reviewed by John Sullivan. + + Improved editor options for prepare-ChangeLog and commit-log-editor + https://bugs.webkit.org/show_bug.cgi?id=40548 + + * Scripts/commit-log-editor: Split editor strings on spaces so EDITOR + values like "xed --launch --wait" work properly. + + * Scripts/prepare-ChangeLog: Added a new CHANGE_LOG_EDITOR so we can + use a command line tool with the $openChangeLogs feature. + +2010-08-11 Yury Semikhatsky <yurys@chromium.org> + + Reviewed by Pavel Feldman. + + Web Inspector: remove InjectDispatch.js + https://bugs.webkit.org/show_bug.cgi?id=43835 + + * DumpRenderTree/chromium/DRTDevToolsAgent.cpp: + * DumpRenderTree/chromium/DRTDevToolsAgent.h: + +2010-08-10 Dirk Pranke <dpranke@chromium.org> + + Reviewed by Eric Seidel. + + webkit-patch should refuse to run under Win32 Python + https://bugs.webkit.org/show_bug.cgi?id=40962 + + Given that there are lots of places in webkit-patch's code that + assume unix-style filenames (forward slashes), webkit-patch fails + with weird file-not-found errors when run under a native windows + Python. It would be nice if we just trapped this and errored out + at the beginning, rather than producing unpredictable errors. + + * Scripts/webkit-patch: + +2010-08-10 Kent Tamura <tkent@chromium.org> + + Unreviewed, build fix. + + Chromium build fix for r65107. + + * DumpRenderTree/chromium/LayoutTestController.cpp: + (LayoutTestController::suspendAnimations): + (LayoutTestController::resumeAnimations): + +2010-08-10 Sergio Villar Senin <svillar@igalia.com> + + Reviewed by Xan Lopez. + + [GTK] http/tests/media/video-cookie.html fails + https://bugs.webkit.org/show_bug.cgi?id=42240 + + * DumpRenderTree/gtk/LayoutTestControllerGtk.cpp: + (LayoutTestController::setAlwaysAcceptCookies): create the + SoupCookieJar if it does not exist. Otherwise the accept policy + won't be set. + +2010-08-10 Chris Marrin <cmarrin@apple.com> + + Reviewed by Oliver Hunt. + + Add suspendAnimations/resumeAnimation API to DRT + https://bugs.webkit.org/show_bug.cgi?id=43733 + + Adds suspendAnimations() and resumeAnimations() to LayoutTestController. + Calls functions with the same names on AnimationController for the + mainFrame. + + * DumpRenderTree/DumpRenderTree.xcodeproj/project.pbxproj: + * DumpRenderTree/LayoutTestController.cpp: + (suspendAnimationsCallback): + (resumeAnimationsCallback): + (LayoutTestController::staticFunctions): + * DumpRenderTree/LayoutTestController.h: + * DumpRenderTree/chromium/LayoutTestController.cpp: + (LayoutTestController::LayoutTestController): + (LayoutTestController::suspendAnimations): + (LayoutTestController::resumeAnimations): + * DumpRenderTree/chromium/LayoutTestController.h: + * DumpRenderTree/gtk/LayoutTestControllerGtk.cpp: + (LayoutTestController::suspendAnimations): + (LayoutTestController::resumeAnimations): + * DumpRenderTree/mac/LayoutTestControllerMac.mm: + (LayoutTestController::suspendAnimations): + (LayoutTestController::resumeAnimations): + * DumpRenderTree/qt/LayoutTestControllerQt.cpp: + (LayoutTestController::suspendAnimations): + (LayoutTestController::resumeAnimations): + * DumpRenderTree/qt/LayoutTestControllerQt.h: + * DumpRenderTree/win/LayoutTestControllerWin.cpp: + (LayoutTestController::suspendAnimations): + (LayoutTestController::resumeAnimations): + * DumpRenderTree/wx/LayoutTestControllerWx.cpp: + (LayoutTestController::suspendAnimations): + (LayoutTestController::resumeAnimations): + +2010-08-10 Dimitri Glazkov <dglazkov@chromium.org> + + Reviewed by Ojan Vafai. + + [Chromium/DRT] Enable saving layout test results. + https://bugs.webkit.org/show_bug.cgi?id=43796 + + * BuildSlaveSupport/build.webkit.org-config/master.cfg: Added more + parameters to the new-run-webkit-tests, including the name + of the test results server. + +2010-08-10 Jian Li <jianli@chromium.org> + + More chromium build fix. + + * DumpRenderTree/chromium/MockSpellCheck.cpp: + (MockSpellCheck::spellCheckWord): + (MockSpellCheck::initializeIfNeeded): + * DumpRenderTree/chromium/NotificationPresenter.cpp: + (NotificationPresenter::grantPermission): + (NotificationPresenter::show): + (NotificationPresenter::checkPermission): + +2010-08-10 Jian Li <jianli@chromium.org> + + Chromium build fix. + + * DumpRenderTree/chromium/MockSpellCheck.cpp: + * DumpRenderTree/chromium/NotificationPresenter.cpp: + +2010-08-10 Victor Wang <victorw@chromium.org> + + Reviewed by Ojan Vafai. + + Update test results server merge logic so the aggregated + results and times are updated for tests that are + in aggragated json but not in incremental json. + + Also update unittest to test this case. + + https://bugs.webkit.org/show_bug.cgi?id=43769 + + * TestResultServer/model/jsonresults.py: + * TestResultServer/model/jsonresults_unittest.py: + 2010-08-09 Antonio Gomes <tonikitoo@webkit.org> Reviewed by Ariya Hidayat. diff --git a/WebKitTools/DumpRenderTree/LayoutTestController.cpp b/WebKitTools/DumpRenderTree/LayoutTestController.cpp index 52b539c..700b44c 100644 --- a/WebKitTools/DumpRenderTree/LayoutTestController.cpp +++ b/WebKitTools/DumpRenderTree/LayoutTestController.cpp @@ -1545,6 +1545,20 @@ static JSValueRef numberOfActiveAnimationsCallback(JSContextRef context, JSObjec return JSValueMakeNumber(context, controller->numberOfActiveAnimations()); } +static JSValueRef suspendAnimationsCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject)); + controller->suspendAnimations(); + return JSValueMakeUndefined(context); +} + +static JSValueRef resumeAnimationsCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject)); + controller->resumeAnimations(); + return JSValueMakeUndefined(context); +} + static JSValueRef waitForPolicyDelegateCallback(JSContextRef context, JSObjectRef, JSObjectRef thisObject, size_t, const JSValueRef[], JSValueRef*) { LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject)); @@ -1850,6 +1864,8 @@ JSStaticFunction* LayoutTestController::staticFunctions() { "markerTextForListItem", markerTextForListItemCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, { "notifyDone", notifyDoneCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, { "numberOfActiveAnimations", numberOfActiveAnimationsCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "suspendAnimations", suspendAnimationsCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "resumeAnimations", resumeAnimationsCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, { "overridePreference", overridePreferenceCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, { "pageNumberForElementById", pageNumberForElementByIdCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, { "pageSizeAndMarginsInPixels", pageSizeAndMarginsInPixelsCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, diff --git a/WebKitTools/DumpRenderTree/LayoutTestController.h b/WebKitTools/DumpRenderTree/LayoutTestController.h index f76870b..2bab542 100644 --- a/WebKitTools/DumpRenderTree/LayoutTestController.h +++ b/WebKitTools/DumpRenderTree/LayoutTestController.h @@ -251,6 +251,8 @@ public: bool pauseTransitionAtTimeOnElementWithId(JSStringRef propertyName, double time, JSStringRef elementId); bool sampleSVGAnimationForElementAtTime(JSStringRef animationId, double time, JSStringRef elementId); unsigned numberOfActiveAnimations() const; + void suspendAnimations() const; + void resumeAnimations() const; void addOriginAccessWhitelistEntry(JSStringRef sourceOrigin, JSStringRef destinationProtocol, JSStringRef destinationHost, bool allowDestinationSubdomains); void removeOriginAccessWhitelistEntry(JSStringRef sourceOrigin, JSStringRef destinationProtocol, JSStringRef destinationHost, bool allowDestinationSubdomains); diff --git a/WebKitTools/DumpRenderTree/chromium/DRTDevToolsAgent.cpp b/WebKitTools/DumpRenderTree/chromium/DRTDevToolsAgent.cpp index b05fe21..4736676 100644 --- a/WebKitTools/DumpRenderTree/chromium/DRTDevToolsAgent.cpp +++ b/WebKitTools/DumpRenderTree/chromium/DRTDevToolsAgent.cpp @@ -84,11 +84,6 @@ WebCString DRTDevToolsAgent::injectedScriptSource() return webkit_support::GetDevToolsInjectedScriptSource(); } -WebCString DRTDevToolsAgent::injectedScriptDispatcherSource() -{ - return webkit_support::GetDevToolsInjectedScriptDispatcherSource(); -} - WebCString DRTDevToolsAgent::debuggerScriptSource() { return webkit_support::GetDevToolsDebuggerScriptSource(); diff --git a/WebKitTools/DumpRenderTree/chromium/DRTDevToolsAgent.h b/WebKitTools/DumpRenderTree/chromium/DRTDevToolsAgent.h index df52866..899a23f 100644 --- a/WebKitTools/DumpRenderTree/chromium/DRTDevToolsAgent.h +++ b/WebKitTools/DumpRenderTree/chromium/DRTDevToolsAgent.h @@ -62,7 +62,6 @@ public: virtual void forceRepaint(); virtual void runtimeFeatureStateChanged(const WebKit::WebString& feature, bool enabled); virtual WebKit::WebCString injectedScriptSource(); - virtual WebKit::WebCString injectedScriptDispatcherSource(); virtual WebKit::WebCString debuggerScriptSource(); void asyncCall(const DRTDevToolsCallArgs&); diff --git a/WebKitTools/DumpRenderTree/chromium/LayoutTestController.cpp b/WebKitTools/DumpRenderTree/chromium/LayoutTestController.cpp index e82a65e..beae21e 100644 --- a/WebKitTools/DumpRenderTree/chromium/LayoutTestController.cpp +++ b/WebKitTools/DumpRenderTree/chromium/LayoutTestController.cpp @@ -117,6 +117,8 @@ LayoutTestController::LayoutTestController(TestShell* shell) bindMethod("pauseTransitionAtTimeOnElementWithId", &LayoutTestController::pauseTransitionAtTimeOnElementWithId); bindMethod("elementDoesAutoCompleteForElementWithId", &LayoutTestController::elementDoesAutoCompleteForElementWithId); bindMethod("numberOfActiveAnimations", &LayoutTestController::numberOfActiveAnimations); + bindMethod("suspendAnimations", &LayoutTestController::suspendAnimations); + bindMethod("resumeAnimations", &LayoutTestController::resumeAnimations); bindMethod("disableImageLoading", &LayoutTestController::disableImageLoading); bindMethod("setIconDatabaseEnabled", &LayoutTestController::setIconDatabaseEnabled); bindMethod("setCustomPolicyDelegate", &LayoutTestController::setCustomPolicyDelegate); @@ -838,6 +840,32 @@ int LayoutTestController::numberOfActiveAnimations() return controller->numberOfActiveAnimations(); } +void LayoutTestController::suspendAnimations() +{ + WebFrame* webFrame = m_shell->webView()->mainFrame(); + if (!webFrame) + return; + + WebAnimationController* controller = webFrame->animationController(); + if (!controller) + return; + + controller->suspendAnimations(); +} + +void LayoutTestController::resumeAnimations() +{ + WebFrame* webFrame = m_shell->webView()->mainFrame(); + if (!webFrame) + return; + + WebAnimationController* controller = webFrame->animationController(); + if (!controller) + return; + + controller->resumeAnimations(); +} + void LayoutTestController::pauseAnimationAtTimeOnElementWithId(const CppArgumentList& arguments, CppVariant* result) { result->set(false); @@ -875,6 +903,18 @@ void LayoutTestController::numberOfActiveAnimations(const CppArgumentList&, CppV result->set(numberOfActiveAnimations()); } +void LayoutTestController::suspendAnimations(const CppArgumentList&, CppVariant* result) +{ + suspendAnimations(); + result->setNull(); +} + +void LayoutTestController::resumeAnimations(const CppArgumentList&, CppVariant* result) +{ + resumeAnimations(); + result->setNull(); +} + void LayoutTestController::disableImageLoading(const CppArgumentList&, CppVariant* result) { m_shell->webView()->settings()->setLoadsImagesAutomatically(false); diff --git a/WebKitTools/DumpRenderTree/chromium/LayoutTestController.h b/WebKitTools/DumpRenderTree/chromium/LayoutTestController.h index fb91544..352e89f 100644 --- a/WebKitTools/DumpRenderTree/chromium/LayoutTestController.h +++ b/WebKitTools/DumpRenderTree/chromium/LayoutTestController.h @@ -207,6 +207,8 @@ public: void pauseTransitionAtTimeOnElementWithId(const CppArgumentList&, CppVariant*); void elementDoesAutoCompleteForElementWithId(const CppArgumentList&, CppVariant*); void numberOfActiveAnimations(const CppArgumentList&, CppVariant*); + void suspendAnimations(const CppArgumentList&, CppVariant*); + void resumeAnimations(const CppArgumentList&, CppVariant*); void disableImageLoading(const CppArgumentList&, CppVariant*); @@ -395,6 +397,8 @@ private: bool pauseTransitionAtTimeOnElementWithId(const WebKit::WebString& propertyName, double time, const WebKit::WebString& elementId); bool elementDoesAutoCompleteForElementWithId(const WebKit::WebString&); int numberOfActiveAnimations(); + void suspendAnimations(); + void resumeAnimations(); // Used for test timeouts. ScopedRunnableMethodFactory<LayoutTestController> m_timeoutFactory; diff --git a/WebKitTools/DumpRenderTree/chromium/MockSpellCheck.cpp b/WebKitTools/DumpRenderTree/chromium/MockSpellCheck.cpp index fe70cab..0bf3802 100644 --- a/WebKitTools/DumpRenderTree/chromium/MockSpellCheck.cpp +++ b/WebKitTools/DumpRenderTree/chromium/MockSpellCheck.cpp @@ -31,11 +31,12 @@ #include "config.h" #include "MockSpellCheck.h" -#include "public/WebString.h" #include <wtf/ASCIICType.h> #include <wtf/Assertions.h> +#include <wtf/text/WTFString.h> + +#include "public/WebString.h" -using namespace WebCore; using namespace WebKit; MockSpellCheck::MockSpellCheck() @@ -59,7 +60,7 @@ bool MockSpellCheck::spellCheckWord(const WebString& text, int* misspelledOffset // Convert to a String because we store String instances in // m_misspelledWords and WebString has no find(). - const String stringText(text.data(), text.length()); + const WTF::String stringText(text.data(), text.length()); // Extract the first possible English word from the given string. // The given string may include non-ASCII characters or numbers. So, we @@ -82,7 +83,7 @@ bool MockSpellCheck::spellCheckWord(const WebString& text, int* misspelledOffset // extracted word if this word is a known misspelled word. // (See the comment in MockSpellCheck::initializeIfNeeded() why we use a // misspelled-word table.) - String word = stringText.substring(wordOffset, wordLength); + WTF::String word = stringText.substring(wordOffset, wordLength); if (!m_misspelledWords.contains(word)) return true; @@ -137,7 +138,7 @@ bool MockSpellCheck::initializeIfNeeded() m_misspelledWords.clear(); for (size_t i = 0; i < arraysize(misspelledWords); ++i) - m_misspelledWords.add(String::fromUTF8(misspelledWords[i]), false); + m_misspelledWords.add(WTF::String::fromUTF8(misspelledWords[i]), false); // Mark as initialized to prevent this object from being initialized twice // or more. diff --git a/WebKitTools/DumpRenderTree/chromium/NotificationPresenter.cpp b/WebKitTools/DumpRenderTree/chromium/NotificationPresenter.cpp index 86903be..95353a7 100644 --- a/WebKitTools/DumpRenderTree/chromium/NotificationPresenter.cpp +++ b/WebKitTools/DumpRenderTree/chromium/NotificationPresenter.cpp @@ -31,36 +31,37 @@ #include "config.h" #include "NotificationPresenter.h" +#include <wtf/text/CString.h> +#include <wtf/text/WTFString.h> + #include "googleurl/src/gurl.h" #include "public/WebNotification.h" #include "public/WebNotificationPermissionCallback.h" #include "public/WebSecurityOrigin.h" #include "public/WebString.h" #include "public/WebURL.h" -#include <wtf/text/CString.h> -using namespace WebCore; using namespace WebKit; void NotificationPresenter::grantPermission(const WebString& origin) { // Make sure it's in the form of an origin. GURL url(origin); - m_allowedOrigins.add(String(url.GetOrigin().spec().c_str())); + m_allowedOrigins.add(WTF::String(url.GetOrigin().spec().c_str())); } // The output from all these methods matches what DumpRenderTree produces. bool NotificationPresenter::show(const WebNotification& notification) { if (!notification.replaceId().isEmpty()) { - String replaceId(notification.replaceId().data(), notification.replaceId().length()); + WTF::String replaceId(notification.replaceId().data(), notification.replaceId().length()); if (m_replacements.find(replaceId) != m_replacements.end()) printf("REPLACING NOTIFICATION %s\n", m_replacements.find(replaceId)->second.utf8().data()); WebString identifier = notification.isHTML() ? notification.url().spec().utf16() : notification.title(); - m_replacements.set(replaceId, String(identifier.data(), identifier.length())); + m_replacements.set(replaceId, WTF::String(identifier.data(), identifier.length())); } if (notification.isHTML()) { @@ -103,7 +104,7 @@ void NotificationPresenter::objectDestroyed(const WebKit::WebNotification& notif WebNotificationPresenter::Permission NotificationPresenter::checkPermission(const WebURL& url) { // Check with the layout test controller - String origin = String(static_cast<GURL>(url).GetOrigin().spec().c_str()); + WTF::String origin = WTF::String(static_cast<GURL>(url).GetOrigin().spec().c_str()); bool allowed = m_allowedOrigins.find(origin) != m_allowedOrigins.end(); return allowed ? WebNotificationPresenter::PermissionAllowed : WebNotificationPresenter::PermissionDenied; diff --git a/WebKitTools/DumpRenderTree/chromium/TestShell.cpp b/WebKitTools/DumpRenderTree/chromium/TestShell.cpp index 64c20b0..7ea36e1 100644 --- a/WebKitTools/DumpRenderTree/chromium/TestShell.cpp +++ b/WebKitTools/DumpRenderTree/chromium/TestShell.cpp @@ -225,6 +225,8 @@ void TestShell::resetWebSettings(WebView& webView) #else settings->setEditingBehavior(WebSettings::EditingBehaviorWin); #endif + // FIXME: crbug.com/51879 + settings->setAcceleratedCompositingEnabled(false); } void TestShell::runFileTest(const TestParams& params) diff --git a/WebKitTools/DumpRenderTree/gtk/LayoutTestControllerGtk.cpp b/WebKitTools/DumpRenderTree/gtk/LayoutTestControllerGtk.cpp index b0c1cba..db44a60 100644 --- a/WebKitTools/DumpRenderTree/gtk/LayoutTestControllerGtk.cpp +++ b/WebKitTools/DumpRenderTree/gtk/LayoutTestControllerGtk.cpp @@ -52,6 +52,8 @@ bool webkit_web_frame_pause_animation(WebKitWebFrame* frame, const gchar* name, bool webkit_web_frame_pause_transition(WebKitWebFrame* frame, const gchar* name, double time, const gchar* element); bool webkit_web_frame_pause_svg_animation(WebKitWebFrame* frame, const gchar* name, double time, const gchar* element); unsigned int webkit_web_frame_number_of_active_animations(WebKitWebFrame* frame); +void webkit_web_frame_suspend_animations(WebKitWebFrame* frame); +void webkit_web_frame_resume_animations(WebKitWebFrame* frame); void webkit_application_cache_set_maximum_size(unsigned long long size); unsigned int webkit_worker_thread_count(void); void webkit_white_list_access_from_origin(const gchar* sourceOrigin, const gchar* destinationProtocol, const gchar* destinationHost, bool allowDestinationSubdomains); @@ -250,6 +252,15 @@ void LayoutTestController::setAlwaysAcceptCookies(bool alwaysAcceptCookies) SoupSession* session = webkit_get_default_session(); SoupCookieJar* jar = reinterpret_cast<SoupCookieJar*>(soup_session_get_feature(session, SOUP_TYPE_COOKIE_JAR)); + /* If the jar was not created - we create it on demand, i.e, just + in case we have HTTP requests - then we must create it here in + order to set the proper accept policy */ + if (!jar) { + jar = soup_cookie_jar_new(); + soup_session_add_feature(session, SOUP_SESSION_FEATURE(jar)); + g_object_unref(jar); + } + SoupCookieJarAcceptPolicy policy; if (alwaysAcceptCookies) @@ -620,6 +631,16 @@ unsigned LayoutTestController::numberOfActiveAnimations() const return webkit_web_frame_number_of_active_animations(mainFrame); } +void LayoutTestController::suspendAnimations() const +{ + webkit_web_frame_suspend_animations(mainFrame); +} + +void LayoutTestController::resumeAnimations() const +{ + webkit_web_frame_resume_animations(mainFrame); +} + void LayoutTestController::overridePreference(JSStringRef key, JSStringRef value) { gchar* name = JSStringCopyUTF8CString(key); diff --git a/WebKitTools/DumpRenderTree/mac/LayoutTestControllerMac.mm b/WebKitTools/DumpRenderTree/mac/LayoutTestControllerMac.mm index c0eb722..a85ac2e 100644 --- a/WebKitTools/DumpRenderTree/mac/LayoutTestControllerMac.mm +++ b/WebKitTools/DumpRenderTree/mac/LayoutTestControllerMac.mm @@ -631,6 +631,16 @@ unsigned LayoutTestController::numberOfActiveAnimations() const return [mainFrame _numberOfActiveAnimations]; } +void LayoutTestController::suspendAnimations() const +{ + return [mainFrame _suspendAnimations]; +} + +void LayoutTestController::resumeAnimations() const +{ + return [mainFrame _resumeAnimations]; +} + void LayoutTestController::waitForPolicyDelegate() { setWaitToDump(true); diff --git a/WebKitTools/DumpRenderTree/qt/DumpRenderTreeQt.cpp b/WebKitTools/DumpRenderTree/qt/DumpRenderTreeQt.cpp index c6c39b5..4a57d1d 100644 --- a/WebKitTools/DumpRenderTree/qt/DumpRenderTreeQt.cpp +++ b/WebKitTools/DumpRenderTree/qt/DumpRenderTreeQt.cpp @@ -571,7 +571,7 @@ void DumpRenderTree::open(const QUrl& url) m_page->event(&ev); QWebSettings::clearMemoryCaches(); -#if !(defined(Q_WS_S60) && QT_VERSION <= QT_VERSION_CHECK(4, 6, 2)) +#if !(defined(Q_OS_SYMBIAN) && QT_VERSION <= QT_VERSION_CHECK(4, 6, 2)) QFontDatabase::removeAllApplicationFonts(); #endif #if defined(Q_WS_X11) diff --git a/WebKitTools/DumpRenderTree/qt/LayoutTestControllerQt.cpp b/WebKitTools/DumpRenderTree/qt/LayoutTestControllerQt.cpp index e682fd0..74baf37 100644 --- a/WebKitTools/DumpRenderTree/qt/LayoutTestControllerQt.cpp +++ b/WebKitTools/DumpRenderTree/qt/LayoutTestControllerQt.cpp @@ -484,6 +484,20 @@ unsigned LayoutTestController::numberOfActiveAnimations() const return DumpRenderTreeSupportQt::numberOfActiveAnimations(frame); } +void LayoutTestController::suspendAnimations() const +{ + QWebFrame* frame = m_drt->webPage()->mainFrame(); + Q_ASSERT(frame); + DumpRenderTreeSupportQt::suspendAnimations(frame); +} + +void LayoutTestController::resumeAnimations() const +{ + QWebFrame* frame = m_drt->webPage()->mainFrame(); + Q_ASSERT(frame); + DumpRenderTreeSupportQt::resumeAnimations(frame); +} + void LayoutTestController::disableImageLoading() { m_drt->webPage()->settings()->setAttribute(QWebSettings::AutoLoadImages, false); diff --git a/WebKitTools/DumpRenderTree/qt/LayoutTestControllerQt.h b/WebKitTools/DumpRenderTree/qt/LayoutTestControllerQt.h index f9986b1..207e093 100644 --- a/WebKitTools/DumpRenderTree/qt/LayoutTestControllerQt.h +++ b/WebKitTools/DumpRenderTree/qt/LayoutTestControllerQt.h @@ -167,6 +167,8 @@ public slots: bool elementDoesAutoCompleteForElementWithId(const QString& elementId); unsigned numberOfActiveAnimations() const; + void suspendAnimations() const; + void resumeAnimations() const; void addOriginAccessWhitelistEntry(const QString& sourceOrigin, const QString& destinationProtocol, const QString& destinationHost, bool allowDestinationSubdomains); void removeOriginAccessWhitelistEntry(const QString& sourceOrigin, const QString& destinationProtocol, const QString& destinationHost, bool allowDestinationSubdomains); diff --git a/WebKitTools/DumpRenderTree/win/DumpRenderTree.cpp b/WebKitTools/DumpRenderTree/win/DumpRenderTree.cpp index a1b72e1..67e5d4b 100644 --- a/WebKitTools/DumpRenderTree/win/DumpRenderTree.cpp +++ b/WebKitTools/DumpRenderTree/win/DumpRenderTree.cpp @@ -1232,8 +1232,17 @@ RetainPtr<CFURLCacheRef> sharedCFURLCache() } #endif +static LONG WINAPI exceptionFilter(EXCEPTION_POINTERS*) +{ + fputs("#CRASHED\n", stderr); + fflush(stderr); + return EXCEPTION_CONTINUE_SEARCH; +} + int main(int argc, char* argv[]) { + ::SetUnhandledExceptionFilter(exceptionFilter); + leakChecking = false; _setmode(1, _O_BINARY); diff --git a/WebKitTools/DumpRenderTree/win/LayoutTestControllerWin.cpp b/WebKitTools/DumpRenderTree/win/LayoutTestControllerWin.cpp index 31bc6ce..1ff88e5 100644 --- a/WebKitTools/DumpRenderTree/win/LayoutTestControllerWin.cpp +++ b/WebKitTools/DumpRenderTree/win/LayoutTestControllerWin.cpp @@ -1060,6 +1060,24 @@ unsigned LayoutTestController::numberOfActiveAnimations() const return number; } +void LayoutTestController::suspendAnimations() const +{ + COMPtr<IWebFramePrivate> framePrivate(Query, frame); + if (!framePrivate) + return; + + framePrivate->suspendAnimations(); +} + +void LayoutTestController::resumeAnimations() const +{ + COMPtr<IWebFramePrivate> framePrivate(Query, frame); + if (!framePrivate) + return; + + framePrivate->resumeAnimations(); +} + static _bstr_t bstrT(JSStringRef jsString) { // The false parameter tells the _bstr_t constructor to adopt the BSTR we pass it. diff --git a/WebKitTools/DumpRenderTree/wscript b/WebKitTools/DumpRenderTree/wscript index 75d208f..4aaedb4 100644 --- a/WebKitTools/DumpRenderTree/wscript +++ b/WebKitTools/DumpRenderTree/wscript @@ -58,8 +58,8 @@ def build(bld): includes = ' '.join(include_paths), source = sources, target = 'DumpRenderTree', - uselib = 'JSCORE ICU WXWEBKIT WX ' + get_config(), + uselib = 'ICU WX ' + get_config(), libpath = [output_dir], - uselib_local = '', + uselib_local = 'jscore wxwebkit', install_path = output_dir) diff --git a/WebKitTools/DumpRenderTree/wx/LayoutTestControllerWx.cpp b/WebKitTools/DumpRenderTree/wx/LayoutTestControllerWx.cpp index 7c80ff2..9fee1e3 100644 --- a/WebKitTools/DumpRenderTree/wx/LayoutTestControllerWx.cpp +++ b/WebKitTools/DumpRenderTree/wx/LayoutTestControllerWx.cpp @@ -264,6 +264,16 @@ unsigned LayoutTestController::numberOfActiveAnimations() const return 0; } +void LayoutTestController::suspendAnimations() const +{ + // FIXME: implement +} + +void LayoutTestController::resumeAnimations() const +{ + // FIXME: implement +} + unsigned LayoutTestController::workerThreadCount() const { // FIXME: implement diff --git a/WebKitTools/MiniBrowser/mac/BrowserWindowController.m b/WebKitTools/MiniBrowser/mac/BrowserWindowController.m index 9a987d2..9842448 100644 --- a/WebKitTools/MiniBrowser/mac/BrowserWindowController.m +++ b/WebKitTools/MiniBrowser/mac/BrowserWindowController.m @@ -411,7 +411,8 @@ static WKStringRef runJavaScriptPrompt(WKPageRef page, WKStringRef message, WKSt closePage, runJavaScriptAlert, runJavaScriptConfirm, - runJavaScriptPrompt + runJavaScriptPrompt, + 0 /* contentsSizeChanged */ }; WKPageSetPageUIClient(_webView.pageRef, &uiClient); } diff --git a/WebKitTools/MiniBrowser/win/BrowserView.cpp b/WebKitTools/MiniBrowser/win/BrowserView.cpp index 49e46bf..ee67a08 100644 --- a/WebKitTools/MiniBrowser/win/BrowserView.cpp +++ b/WebKitTools/MiniBrowser/win/BrowserView.cpp @@ -83,7 +83,8 @@ void BrowserView::create(RECT webViewRect, BrowserWindow* parentWindow) createNewPage, showPage, closePage, - runJavaScriptAlert + runJavaScriptAlert, + 0 /* contentsSizeChanged */ }; WKPageSetPageUIClient(WKViewGetPage(m_webView), &uiClient); } diff --git a/WebKitTools/QtTestBrowser/launcherwindow.cpp b/WebKitTools/QtTestBrowser/launcherwindow.cpp index 095a984..9b7aa0d 100644 --- a/WebKitTools/QtTestBrowser/launcherwindow.cpp +++ b/WebKitTools/QtTestBrowser/launcherwindow.cpp @@ -65,7 +65,7 @@ void LauncherWindow::init() QSplitter* splitter = new QSplitter(Qt::Vertical, this); setCentralWidget(splitter); -#if defined(Q_WS_S60) +#if defined(Q_OS_SYMBIAN) setWindowState(Qt::WindowMaximized); #else setWindowState(Qt::WindowNoState); @@ -218,7 +218,7 @@ void LauncherWindow::createChrome() QMenu* toolsMenu = menuBar()->addMenu("&Develop"); QMenu* graphicsViewMenu = toolsMenu->addMenu("QGraphicsView"); - QAction* toggleGraphicsView = graphicsViewMenu->addAction("Toggle use of QGraphicsView", this, SLOT(initializeView())); + QAction* toggleGraphicsView = graphicsViewMenu->addAction("Toggle use of QGraphicsView", this, SLOT(toggleWebView(bool))); toggleGraphicsView->setCheckable(true); toggleGraphicsView->setChecked(isGraphicsBased()); @@ -339,16 +339,12 @@ void LauncherWindow::createChrome() QAction* flipAnimated = graphicsViewMenu->addAction("Animated Flip"); flipAnimated->connect(toggleGraphicsView, SIGNAL(toggled(bool)), SLOT(setEnabled(bool))); flipAnimated->setEnabled(isGraphicsBased()); + connect(flipAnimated, SIGNAL(triggered()), SLOT(animatedFlip())); QAction* flipYAnimated = graphicsViewMenu->addAction("Animated Y-Flip"); flipYAnimated->connect(toggleGraphicsView, SIGNAL(toggled(bool)), SLOT(setEnabled(bool))); flipYAnimated->setEnabled(isGraphicsBased()); - - if (isGraphicsBased()) { - WebViewGraphicsBased* view = static_cast<WebViewGraphicsBased*>(m_view); - connect(flipAnimated, SIGNAL(triggered()), view, SLOT(animatedFlip())); - connect(flipYAnimated, SIGNAL(triggered()), view, SLOT(animatedYFlip())); - } + connect(flipYAnimated, SIGNAL(triggered()), SLOT(animatedYFlip())); QAction* cloneWindow = graphicsViewMenu->addAction("Clone Window", this, SLOT(cloneWindow())); cloneWindow->connect(toggleGraphicsView, SIGNAL(toggled(bool)), SLOT(setEnabled(bool))); @@ -669,6 +665,12 @@ void LauncherWindow::setTouchMocking(bool on) #endif } +void LauncherWindow::toggleWebView(bool graphicsBased) +{ + m_windowOptions.useGraphicsView = graphicsBased; + initializeView(); +} + void LauncherWindow::toggleAcceleratedCompositing(bool toggle) { m_windowOptions.useCompositing = toggle; @@ -692,6 +694,15 @@ void LauncherWindow::toggleWebGL(bool toggle) page()->settings()->setAttribute(QWebSettings::WebGLEnabled, toggle); } +void LauncherWindow::animatedFlip() +{ + qobject_cast<WebViewGraphicsBased*>(m_view)->animatedFlip(); +} + +void LauncherWindow::animatedYFlip() +{ + qobject_cast<WebViewGraphicsBased*>(m_view)->animatedYFlip(); +} void LauncherWindow::toggleSpatialNavigation(bool b) { page()->settings()->setAttribute(QWebSettings::SpatialNavigationEnabled, b); @@ -702,7 +713,7 @@ void LauncherWindow::toggleFullScreenMode(bool enable) if (enable) setWindowState(Qt::WindowFullScreen); else { -#if defined(Q_WS_S60) +#if defined(Q_OS_SYMBIAN) setWindowState(Qt::WindowMaximized); #else setWindowState(Qt::WindowNoState); @@ -760,7 +771,7 @@ void LauncherWindow::showFPS(bool enable) view->setFrameRateMeasurementEnabled(enable); if (!enable) { -#if defined(Q_WS_MAEMO_5) && defined(Q_WS_S60) +#if defined(Q_WS_MAEMO_5) && defined(Q_OS_SYMBIAN) setWindowTitle(""); #else statusBar()->clearMessage(); @@ -819,7 +830,7 @@ void LauncherWindow::updateFPS(int fps) { QString fpsStatusText = QString("Current FPS: %1").arg(fps); -#if defined(Q_WS_MAEMO_5) && defined(Q_WS_S60) +#if defined(Q_WS_MAEMO_5) && defined(Q_OS_SYMBIAN) setWindowTitle(fpsStatusText); #else statusBar()->showMessage(fpsStatusText); diff --git a/WebKitTools/QtTestBrowser/launcherwindow.h b/WebKitTools/QtTestBrowser/launcherwindow.h index 9319d24..65f390d 100644 --- a/WebKitTools/QtTestBrowser/launcherwindow.h +++ b/WebKitTools/QtTestBrowser/launcherwindow.h @@ -82,7 +82,7 @@ public: , useCompositing(true) , useTiledBackingStore(false) , useWebGL(false) -#if defined(Q_WS_MAEMO_5) || defined(Q_WS_S60) +#if defined(Q_WS_MAEMO_5) || defined(Q_OS_SYMBIAN) , useFrameFlattening(true) #else , useFrameFlattening(false) @@ -151,6 +151,7 @@ protected slots: void initializeView(); void setTouchMocking(bool on); + void toggleWebView(bool graphicsBased); void toggleAcceleratedCompositing(bool toggle); void toggleTiledBackingStore(bool toggle); void toggleResizesToContents(bool toggle); @@ -166,6 +167,8 @@ protected slots: #endif void changeViewportUpdateMode(int mode); + void animatedFlip(); + void animatedYFlip(); void selectElements(); void showFPS(bool enable); void showUserAgentDialog(); diff --git a/WebKitTools/QtTestBrowser/mainwindow.cpp b/WebKitTools/QtTestBrowser/mainwindow.cpp index abb608f..1a9aa5f 100644 --- a/WebKitTools/QtTestBrowser/mainwindow.cpp +++ b/WebKitTools/QtTestBrowser/mainwindow.cpp @@ -48,7 +48,7 @@ MainWindow::MainWindow(const QString& url) void MainWindow::buildUI() { QToolBar* bar = addToolBar("Navigation"); -#if defined(Q_WS_S60) +#if defined(Q_OS_SYMBIAN) bar->setIconSize(QSize(16, 16)); #endif QAction* reloadAction = page()->action(QWebPage::Reload); @@ -65,7 +65,7 @@ void MainWindow::buildUI() QCompleter* completer = new QCompleter(this); urlEdit->setCompleter(completer); completer->setModel(&urlModel); -#if defined(Q_WS_S60) +#if defined(Q_OS_SYMBIAN) addToolBarBreak(); addToolBar("Location")->addWidget(urlEdit); #else diff --git a/WebKitTools/QtTestBrowser/webview.cpp b/WebKitTools/QtTestBrowser/webview.cpp index c8eecd6..bc8fad1 100644 --- a/WebKitTools/QtTestBrowser/webview.cpp +++ b/WebKitTools/QtTestBrowser/webview.cpp @@ -42,6 +42,7 @@ WebViewGraphicsBased::WebViewGraphicsBased(QWidget* parent) , m_numPaintsSinceLastMeasure(0) , m_measureFps(false) , m_resizesToContents(false) + , m_machine(0) { setScene(new QGraphicsScene(this)); scene()->addItem(m_item); @@ -50,30 +51,6 @@ WebViewGraphicsBased::WebViewGraphicsBased(QWidget* parent) setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); -#if QT_VERSION >= QT_VERSION_CHECK(4, 6, 0) - QStateMachine* machine = new QStateMachine(this); - QState* s0 = new QState(machine); - s0->assignProperty(this, "yRotation", 0); - - QState* s1 = new QState(machine); - s1->assignProperty(this, "yRotation", 90); - - QAbstractTransition* t1 = s0->addTransition(this, SIGNAL(yFlipRequest()), s1); - QPropertyAnimation* yRotationAnim = new QPropertyAnimation(this, "yRotation", this); - yRotationAnim->setDuration(1000); - t1->addAnimation(yRotationAnim); - - QState* s2 = new QState(machine); - s2->assignProperty(this, "yRotation", -90); - s1->addTransition(s1, SIGNAL(propertiesAssigned()), s2); - - QAbstractTransition* t2 = s2->addTransition(s0); - t2->addAnimation(yRotationAnim); - - machine->setInitialState(s0); - machine->start(); -#endif - m_updateTimer = new QTimer(this); m_updateTimer->setInterval(1000); connect(m_updateTimer, SIGNAL(timeout()), this, SLOT(updateFrameRate())); @@ -193,7 +170,39 @@ void WebViewGraphicsBased::animatedFlip() void WebViewGraphicsBased::animatedYFlip() { - emit yFlipRequest(); +#if QT_VERSION >= QT_VERSION_CHECK(4, 6, 0) + if (!m_machine) { + m_machine = new QStateMachine(this); + + QState* s0 = new QState(m_machine); + s0->assignProperty(this, "yRotation", 0); + + QState* s1 = new QState(m_machine); + s1->assignProperty(this, "yRotation", 90); + + QAbstractTransition* t1 = s0->addTransition(s1); + QPropertyAnimation* yRotationAnim = new QPropertyAnimation(this, "yRotation", this); + t1->addAnimation(yRotationAnim); + + QState* s2 = new QState(m_machine); + s2->assignProperty(this, "yRotation", -90); + s1->addTransition(s1, SIGNAL(propertiesAssigned()), s2); + + QState* s3 = new QState(m_machine); + s3->assignProperty(this, "yRotation", 0); + + QAbstractTransition* t2 = s2->addTransition(s3); + t2->addAnimation(yRotationAnim); + + QFinalState* final = new QFinalState(m_machine); + s3->addTransition(s3, SIGNAL(propertiesAssigned()), final); + + m_machine->setInitialState(s0); + yRotationAnim->setDuration(1000); + } + + m_machine->start(); +#endif } void WebViewGraphicsBased::paintEvent(QPaintEvent* event) diff --git a/WebKitTools/QtTestBrowser/webview.h b/WebKitTools/QtTestBrowser/webview.h index 5e7c0c3..d0e1e57 100644 --- a/WebKitTools/QtTestBrowser/webview.h +++ b/WebKitTools/QtTestBrowser/webview.h @@ -41,6 +41,8 @@ #include <QGraphicsWidget> #include <QTime> +class QStateMachine; + class WebViewTraditional : public QWebView { Q_OBJECT @@ -110,7 +112,6 @@ public slots: void contentsSizeChanged(const QSize&); signals: - void yFlipRequest(); void currentFPSUpdated(int fps); private: @@ -123,6 +124,7 @@ private: bool m_measureFps; qreal m_yRotation; bool m_resizesToContents; + QStateMachine* m_machine; FpsTimer m_fpsTimer; }; diff --git a/WebKitTools/Scripts/build-webkit b/WebKitTools/Scripts/build-webkit index 3b8dd9c..acd7736 100755 --- a/WebKitTools/Scripts/build-webkit +++ b/WebKitTools/Scripts/build-webkit @@ -341,6 +341,9 @@ if (isGtk()) { # Apple builds JavaScriptGlue, and only on the Mac. splice @projects, 1, 0, "JavaScriptGlue"; + # ANGLE must come before WebCore + splice @projects, 0, 0, "ANGLE"; + # WebKit2 is only supported in SnowLeopard and later at present. push @projects, ("WebKit2", "WebKitTools/MiniBrowser") if osXVersion()->{"minor"} >= 6; @@ -404,9 +407,13 @@ if (isInspectorFrontend()) { if (isWx()) { downloadWafIfNeeded(); - push @projects, 'WebKitTools/DumpRenderTree'; - push @projects, 'WebKitTools/wx/browser'; - push @projects, 'WebKit/wx/bindings/python'; + @options = (); + if (defined($makeArgs)) { + @options = split(/ /, $makeArgs); + } + @projects = (); + my $result = buildWafProject('.', $clean, @options); + exit exitStatus($result) if exitStatus($result); } if (isChromium()) { @@ -439,16 +446,6 @@ for my $dir (@projects) { if ($dir eq "WebKit") { $result = buildVisualStudioProject("win/WebKit.vcproj/WebKit.sln", $clean); } - } elsif (isWx()) { - @options = (); - if (defined($makeArgs)) { - @options = split(/ /, $makeArgs); - } - if ($dir eq "WebKit" && isWx()) { - chdir 'wx' or die; - } - - $result = buildWafProject($dir, $clean, @options); } if (exitStatus($result)) { diff --git a/WebKitTools/Scripts/commit-log-editor b/WebKitTools/Scripts/commit-log-editor index a642731..1be0fd0 100755 --- a/WebKitTools/Scripts/commit-log-editor +++ b/WebKitTools/Scripts/commit-log-editor @@ -62,26 +62,40 @@ if (!$log) { my $baseDir = baseProductDir(); my $editor = $ENV{SVN_LOG_EDITOR}; -if (!$editor || isCommitLogEditor($editor)) { - $editor = $ENV{CVS_LOG_EDITOR}; -} -if (!$editor || isCommitLogEditor($editor)) { +$editor = $ENV{CVS_LOG_EDITOR} if !$editor; +$editor = "" if isCommitLogEditor($editor); + +my $splitEditor = 1; +if (!$editor) { my $builtEditorApplication = "$baseDir/Release/Commit Log Editor.app/Contents/MacOS/Commit Log Editor"; - $editor = $builtEditorApplication if -x $builtEditorApplication; + if (-x $builtEditorApplication) { + $editor = $builtEditorApplication; + $splitEditor = 0; + } } -if (!$editor || isCommitLogEditor($editor)) { +if (!$editor) { my $builtEditorApplication = "$baseDir/Debug/Commit Log Editor.app/Contents/MacOS/Commit Log Editor"; - $editor = $builtEditorApplication if -x $builtEditorApplication; -} -if (!$editor || isCommitLogEditor($editor)) { - my $installedEditorApplication = "$ENV{HOME}/Applications/Commit Log Editor.app/Contents/MacOS/Commit Log Editor"; - $editor = $installedEditorApplication if -x $installedEditorApplication; + if (-x $builtEditorApplication) { + $editor = $builtEditorApplication; + $splitEditor = 0; + } } -if (!$editor || isCommitLogEditor($editor)) { - $editor = $ENV{EDITOR}; +if (!$editor) { + my $builtEditorApplication = "$ENV{HOME}/Applications/Commit Log Editor.app/Contents/MacOS/Commit Log Editor"; + if (-x $builtEditorApplication) { + $editor = $builtEditorApplication; + $splitEditor = 0; + } } -if (!$editor || isCommitLogEditor($editor)) { - $editor = "/usr/bin/vi"; + +$editor = $ENV{EDITOR} if !$editor; +$editor = "/usr/bin/vi" if !$editor; + +my @editor; +if ($splitEditor) { + @editor = split ' ', $editor; +} else { + @editor = ($editor); } my $inChangesToBeCommitted = !isGit(); @@ -124,9 +138,8 @@ if ($regenerateLog && $existingLog && scalar(@changeLogs) > 0) { $keepExistingLog = 0 if ($key eq "r"); } -# Don't change anything if there's already a log message -# (as can happen with git-commit --amend) -exec $editor, @ARGV if $existingLog && $keepExistingLog; +# Don't change anything if there's already a log message (as can happen with git-commit --amend). +exec (@editor, @ARGV) if $existingLog && $keepExistingLog; my $topLevel = determineVCSRoot(); @@ -248,7 +261,7 @@ if (isGit() && scalar keys %changeLogSort == 0) { print NEWLOG $logContents; close NEWLOG; -system $editor, "$log.edit"; +system (@editor, "$log.edit"); open NEWLOG, "$log.edit" or exit; my $foundComment = 0; diff --git a/WebKitTools/Scripts/create-html-entity-table b/WebKitTools/Scripts/create-html-entity-table new file mode 100755 index 0000000..46c8c52 --- /dev/null +++ b/WebKitTools/Scripts/create-html-entity-table @@ -0,0 +1,183 @@ +#!/usr/bin/env python +# Copyright (c) 2010 Google Inc. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following disclaimer +# in the documentation and/or other materials provided with the +# distribution. +# * Neither the name of Google Inc. nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +import os.path +import string +import sys + +# Hack sys.path to avoid executing webkitpy __init__.py code which may +# use Python 2.5 features. This code needs to run on Python 2.3 in order +# to support Mac OS X Tiger. +scripts_directory = sys.path[0] +sys.path.append("%s/webkitpy/thirdparty" % scripts_directory) + +import simplejson + + +def convert_entity_to_cpp_name(entity): + postfix = "EntityName" + if entity[-1] == ";": + return "%sSemicolon%s" % (entity[:-1], postfix) + return "%s%s" % (entity, postfix) + + +def convert_entity_to_uchar_array(entity): + return "{'%s'}" % "', '".join(entity) + + +def convert_value_to_int(value): + assert(value[0] == "U") + assert(value[1] == "+") + return "0x" + value[2:] + + +def offset_table_entry(offset): + return " &staticEntityTable[%s]," % offset + + +program_name = os.path.basename(__file__) +if len(sys.argv) < 4 or sys.argv[1] != "-o": + print >> sys.stderr, "Usage: %s -o OUTPUT_FILE INPUT_FILE" % program_name + exit(1) + +output_path = sys.argv[2] +input_path = sys.argv[3] + +html_entity_names_file = open(input_path) +entries = simplejson.load(html_entity_names_file) +html_entity_names_file.close() + +entries = sorted(entries, key=lambda entry: entry['entity']) +entity_count = len(entries) + +output_file = open(output_path, "w") + +print >> output_file, """/* + * 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 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 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. + */ + +// THIS FILE IS GENERATED BY WebKitTools/Scripts/create-html-entity-table +// DO NOT EDIT (unless you are a ninja)! + +#include "config.h" +#include "HTMLEntityTable.h" + +namespace WebCore { + +namespace { +""" + +for entry in entries: + print >> output_file, "const UChar %sEntityName[] = %s;" % ( + convert_entity_to_cpp_name(entry["entity"]), + convert_entity_to_uchar_array(entry["entity"])) + +print >> output_file, """ +HTMLEntityTableEntry staticEntityTable[%s] = {""" % entity_count + +index = {} +offset = 0 +for entry in entries: + letter = entry["entity"][0] + if not index.get(letter): + index[letter] = offset + print >> output_file, ' { %sEntityName, %s, %s },' % ( + convert_entity_to_cpp_name(entry["entity"]), + len(entry["entity"]), + convert_value_to_int(entry["value"])) + offset += 1 + +print >> output_file, """}; +""" + +print >> output_file, "const HTMLEntityTableEntry* uppercaseOffset[] = {" +for letter in string.uppercase: + print >> output_file, offset_table_entry(index[letter]) +print >> output_file, offset_table_entry(index['a']) +print >> output_file, """}; + +const HTMLEntityTableEntry* lowercaseOffset[] = {""" +for letter in string.lowercase: + print >> output_file, offset_table_entry(index[letter]) +print >> output_file, offset_table_entry(entity_count) +print >> output_file, """}; + +} + +const HTMLEntityTableEntry* HTMLEntityTable::firstEntryStartingWith(UChar c) +{ + if (c >= 'A' && c <= 'Z') + return uppercaseOffset[c - 'A']; + if (c >= 'a' && c <= 'z') + return lowercaseOffset[c - 'a']; + return 0; +} + +const HTMLEntityTableEntry* HTMLEntityTable::lastEntryStartingWith(UChar c) +{ + if (c >= 'A' && c <= 'Z') + return uppercaseOffset[c - 'A' + 1] - 1; + if (c >= 'a' && c <= 'z') + return lowercaseOffset[c - 'a' + 1] - 1; + return 0; +} + +const HTMLEntityTableEntry* HTMLEntityTable::firstEntry() +{ + return &staticEntityTable[0]; +} + +const HTMLEntityTableEntry* HTMLEntityTable::lastEntry() +{ + return &staticEntityTable[%s - 1]; +} + +} +""" % entity_count diff --git a/WebKitTools/Scripts/deduplicate-tests b/WebKitTools/Scripts/deduplicate-tests new file mode 100644 index 0000000..f0afe13 --- /dev/null +++ b/WebKitTools/Scripts/deduplicate-tests @@ -0,0 +1,84 @@ +#!/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. + +"""deduplicate-tests -- print test results duplicated between platforms. + +If platform/mac-leopard is missing an expected test output, we fall back on +platform/mac. This means it's possible to grow redundant test outputs, +where we have the same expected data in both a platform directory and another +platform it falls back on. + +This command dumps out all such files. You can use it like this: + deduplicate-tests --verbose # print out the duplicated files + deduplicate-tests | xargs git rm # delete them +""" + + +import optparse +import webkitpy.common.system.logutils as logutils +import webkitpy.layout_tests.deduplicate_tests as deduplicate_tests + + +def parse_args(): + """Provides a default set of command line args. + + Returns a tuple of options, args from optparse""" + + configuration_options = [ + optparse.make_option("-v", "--verbose", dest="verbose", + action="store_true", default=False, + help="Verbose output."), + optparse.make_option("-g", "--glob", dest="glob_pattern", + default="*-expected*", + help="Specify the glob to filter the files, defaults to *-expected*."), + ] + + option_list = (configuration_options) + option_parser = optparse.OptionParser(option_list=option_list) + + options, _ = option_parser.parse_args() + + return options + + +def run(options): + logutils.configure_logging() + if options.verbose: + format = ("* %(test)s\n" + "\tredundantly on %(platform)s and %(fallback)s\n" + "\tconsider deleting %(path)s") + else: + format = "%(path)s" + + for dupe in deduplicate_tests.deduplicate(options.glob_pattern): + print(format % dupe) + + +def main(): + options = parse_args() + run(options) + + +if __name__ == '__main__': + main() diff --git a/WebKitTools/Scripts/old-run-webkit-tests b/WebKitTools/Scripts/old-run-webkit-tests index 97ef3dc..68aa6ed 100755 --- a/WebKitTools/Scripts/old-run-webkit-tests +++ b/WebKitTools/Scripts/old-run-webkit-tests @@ -105,12 +105,14 @@ sub readSkippedFiles($); sub recordActualResultsAndDiff($$); sub sampleDumpTool(); sub setFileHandleNonBlocking(*$); +sub setUpWindowsCrashLogSaving(); sub slowestcmp($$); sub splitpath($); sub stopRunningTestsEarlyIfNeeded(); sub stripExtension($); sub stripMetrics($$); sub testCrashedOrTimedOut($$$$$); +sub toCygwinPath($); sub toURL($); sub toWindowsPath($); sub validateSkippedArg($$;$); @@ -149,7 +151,7 @@ my $root; my $runSample = 1; my $shouldCheckLeaks = 0; my $showHelp = 0; -my $stripEditingCallbacks = isCygwin(); +my $stripEditingCallbacks; my $testHTTP = 1; my $testWebSocket = 1; my $testMedia = 1; @@ -184,6 +186,12 @@ my $prettyDiffTag = "pretty-diff"; my $diffsTag = "diffs"; my $errorTag = "stderr"; +# 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 +# presses Ctrl-C before Perl has finished evaluating this whole file. +my $windowsPostMortemDebuggerKey = "/HKLM/SOFTWARE/Microsoft/Windows NT/CurrentVersion/AeDebug"; +my %previousWindowsPostMortemDebuggerValues; + my $realPlatform; my @macPlatforms = ("mac-tiger", "mac-leopard", "mac-snowleopard", "mac"); @@ -355,11 +363,13 @@ if ($useWebKitTestRunner) { $realPlatform = $platform; $platform = "mac-wk2"; } elsif (isAppleWinWebKit()) { + $stripEditingCallbacks = 0 unless defined $stripEditingCallbacks; $realPlatform = $platform; $platform = "win-wk2"; } } +$stripEditingCallbacks = isCygwin() unless defined $stripEditingCallbacks; my $ignoreSkipped = $treatSkipped eq "ignore"; my $skippedOnly = $treatSkipped eq "only"; @@ -380,6 +390,8 @@ $testMedia = 0 if $shouldCheckLeaks && isTiger(); # Generating remote links causes a lot of unnecessary spew on GTK build bot $useRemoteLinksToTests = 0 if isGtk(); +setUpWindowsCrashLogSaving() if isCygwin(); + setConfigurationProductDir(Cwd::abs_path($root)) if (defined($root)); my $productDir = productDir(); $productDir .= "/bin" if isQt(); @@ -1397,6 +1409,7 @@ sub openDumpTool() } elsif (isCygwin()) { $CLEAN_ENV{HOMEDRIVE} = $ENV{'HOMEDRIVE'}; $CLEAN_ENV{HOMEPATH} = $ENV{'HOMEPATH'}; + $CLEAN_ENV{_NT_SYMBOL_PATH} = $ENV{_NT_SYMBOL_PATH}; setPathForRunningWebKitApp(\%CLEAN_ENV); } @@ -1719,6 +1732,14 @@ sub convertPathUsingCygpath($$) return $convertedPath; } +sub toCygwinPath($) +{ + my ($path) = @_; + return unless isCygwin(); + + return convertPathUsingCygpath($path, "-u"); +} + sub toWindowsPath($) { my ($path) = @_; @@ -2069,6 +2090,10 @@ sub readFromDumpToolWithTimer(**) } } if (defined($lineError)) { + if ($lineError =~ /#CRASHED/) { + $status = "crashed"; + last; + } if ($lineError =~ /#EOF/) { $haveSeenEofError = 1; } else { @@ -2345,3 +2370,47 @@ sub stopRunningTestsEarlyIfNeeded() return 0; } + +sub setUpWindowsCrashLogSaving() +{ + return unless isCygwin(); + + unless (defined $ENV{_NT_SYMBOL_PATH}) { + print "The _NT_SYMBOL_PATH environment variable is not set. Crash logs will not be saved.\nSee <http://trac.webkit.org/wiki/BuildingOnWindows#GettingCrashLogs>.\n"; + return; + } + + my $ntsdPath = File::Spec->catfile(toCygwinPath($ENV{PROGRAMFILES}), "Debugging Tools for Windows (x86)", "ntsd.exe"); + unless (-f $ntsdPath) { + $ntsdPath = File::Spec->catfile(toCygwinPath($ENV{SYSTEMROOT}), "system32", "ntsd.exe"); + unless (-f $ntsdPath) { + print STDERR "Can't find ntsd.exe. Crash logs will not be saved.\nSee <http://trac.webkit.org/wiki/BuildingOnWindows#GettingCrashLogs>.\n"; + return; + } + } + + my %values = ( + Debugger => '"' . toWindowsPath($ntsdPath) . '" -p %ld -e %ld -g -lines -c ".logopen /t \"' . toWindowsPath($testResultsDirectory) . '\CrashLog.txt\";!analyze -vv;~*kpn;q"', + Auto => 1 + ); + + foreach my $value (keys %values) { + chomp($previousWindowsPostMortemDebuggerValues{$value} = `regtool get "$windowsPostMortemDebuggerKey/$value"`); + my $result = system "regtool", "set", "-s", "$windowsPostMortemDebuggerKey/$value", $values{$value}; + next unless $result; + + print "Failed to set \"$windowsPostMortemDebuggerKey/$value\". Crash logs will not be saved.\nSee <http://trac.webkit.org/wiki/BuildingOnWindows#GettingCrashLogs>.\n"; + return; + } + + print "Crash logs will be saved to $testResultsDirectory.\n"; +} + +END { + return unless isCygwin(); + + foreach my $value (keys %previousWindowsPostMortemDebuggerValues) { + my $result = system "regtool", "set", "-s", "$windowsPostMortemDebuggerKey/$value", $previousWindowsPostMortemDebuggerValues{$value}; + !$result or print "Failed to restore \"$windowsPostMortemDebuggerKey/$value\" to its previous value \"$previousWindowsPostMortemDebuggerValues{$value}\"\n."; + } +} diff --git a/WebKitTools/Scripts/prepare-ChangeLog b/WebKitTools/Scripts/prepare-ChangeLog index 1488939..45aca1b 100755 --- a/WebKitTools/Scripts/prepare-ChangeLog +++ b/WebKitTools/Scripts/prepare-ChangeLog @@ -433,11 +433,16 @@ if ($spewDiff && @changed_files) { # Open ChangeLogs. if ($openChangeLogs && @logs) { print STDERR " Opening the edited ChangeLog files.\n"; - my $editor = $ENV{"CHANGE_LOG_EDIT_APPLICATION"}; + my $editor = $ENV{CHANGE_LOG_EDITOR}; if ($editor) { - system "open", "-a", $editor, @logs; + system ((split ' ', $editor), @logs); } else { - system "open", "-e", @logs; + $editor = $ENV{CHANGE_LOG_EDIT_APPLICATION}; + if ($editor) { + system "open", "-a", $editor, @logs; + } else { + system "open", "-e", @logs; + } } } diff --git a/WebKitTools/Scripts/webkit-patch b/WebKitTools/Scripts/webkit-patch index 8300b9f..007f919 100755 --- a/WebKitTools/Scripts/webkit-patch +++ b/WebKitTools/Scripts/webkit-patch @@ -38,6 +38,7 @@ import sys from webkitpy.common.system.logutils import configure_logging import webkitpy.python24.versioning as versioning +_log = logging.getLogger("webkit-patch") def main(): # This is a hack to let us enable DEBUG logging as early as possible. @@ -50,6 +51,11 @@ def main(): configure_logging(logging_level=logging_level) versioning.check_version() + + if sys.platform == "win32": + _log.fatal("webkit-patch is only supported under Cygwin Python, " + "not Win32 Python") + sys.exit(1) # Import webkit-patch code only after version-checking so that # script doesn't error out before having a chance to report the diff --git a/WebKitTools/Scripts/webkitdirs.pm b/WebKitTools/Scripts/webkitdirs.pm index 028d63d..6530244 100644 --- a/WebKitTools/Scripts/webkitdirs.pm +++ b/WebKitTools/Scripts/webkitdirs.pm @@ -1302,6 +1302,21 @@ sub autotoolsFlag($$) return $prefix . '-' . $feature; } +sub autogenArgumentsHaveChanged($@) +{ + my ($filename, @currentArguments) = @_; + + if (! -e $filename) { + return 1; + } + + open(AUTOTOOLS_ARGUMENTS, $filename); + chomp(my $previousArguments = <AUTOTOOLS_ARGUMENTS>); + close(AUTOTOOLS_ARGUMENTS); + + return $previousArguments ne join(" ", @currentArguments); +} + sub buildAutotoolsProject($@) { my ($clean, @buildParams) = @_; @@ -1357,8 +1372,16 @@ sub buildAutotoolsProject($@) # If GNUmakefile exists, don't run autogen.sh. The makefile should be # smart enough to track autotools dependencies and re-run autogen.sh # when build files change. + my $autogenArgumentsFile = "previous-autogen-arguments.txt"; my $result; - if (! -e "GNUmakefile") { + if (!(-e "GNUmakefile") or autogenArgumentsHaveChanged($autogenArgumentsFile, @buildArgs)) { + + # Write autogen.sh arguments to a file so that we can detect + # when they change and automatically re-run it. + open(AUTOTOOLS_ARGUMENTS, ">$autogenArgumentsFile"); + print AUTOTOOLS_ARGUMENTS join(" ", @buildArgs); + close(AUTOTOOLS_ARGUMENTS); + print "Calling configure in " . $dir . "\n\n"; print "Installation prefix directory: $prefix\n" if(defined($prefix)); diff --git a/WebKitTools/Scripts/webkitpy/common/checkout/scm.py b/WebKitTools/Scripts/webkitpy/common/checkout/scm.py index 569558a..5a6c48c 100644 --- a/WebKitTools/Scripts/webkitpy/common/checkout/scm.py +++ b/WebKitTools/Scripts/webkitpy/common/checkout/scm.py @@ -38,6 +38,40 @@ from webkitpy.common.system.executive import Executive, run_command, ScriptError from webkitpy.common.system.deprecated_logging import error, log +def find_checkout_root(): + """Returns the current checkout root (as determined by default_scm(). + + Returns the absolute path to the top of the WebKit checkout, or None + if it cannot be determined. + + """ + scm_system = default_scm() + if scm_system: + return scm_system.checkout_root + return None + + +def default_scm(): + """Return the default SCM object as determined by the CWD and running code. + + Returns the default SCM object for the current working directory; if the + CWD is not in a checkout, then we attempt to figure out if the SCM module + itself is part of a checkout, and return that one. If neither is part of + a checkout, None is returned. + + """ + cwd = os.getcwd() + scm_system = detect_scm_system(cwd) + if not scm_system: + script_directory = os.path.abspath(sys.path[0]) + scm_system = detect_scm_system(script_directory) + if scm_system: + log("The current directory (%s) is not a WebKit checkout, using %s" % (cwd, scm_system.checkout_root)) + else: + error("FATAL: Failed to determine the SCM system for either %s or %s" % (cwd, script_directory)) + return scm_system + + def detect_scm_system(path): absolute_path = os.path.abspath(path) diff --git a/WebKitTools/Scripts/webkitpy/common/checkout/scm_unittest.py b/WebKitTools/Scripts/webkitpy/common/checkout/scm_unittest.py index 852f838..87d5539 100644 --- a/WebKitTools/Scripts/webkitpy/common/checkout/scm_unittest.py +++ b/WebKitTools/Scripts/webkitpy/common/checkout/scm_unittest.py @@ -36,6 +36,7 @@ import os import os.path import re import stat +import sys import subprocess import tempfile import unittest @@ -44,10 +45,11 @@ import shutil from datetime import date from webkitpy.common.checkout.api import Checkout -from webkitpy.common.checkout.scm import detect_scm_system, SCM, SVN, CheckoutNeedsUpdate, commit_error_handler, AuthenticationError, AmbiguousCommitError +from webkitpy.common.checkout.scm import detect_scm_system, SCM, SVN, CheckoutNeedsUpdate, commit_error_handler, AuthenticationError, AmbiguousCommitError, find_checkout_root, default_scm from webkitpy.common.config.committers import Committer # FIXME: This should not be needed from webkitpy.common.net.bugzilla import Attachment # FIXME: This should not be needed from webkitpy.common.system.executive import Executive, run_command, ScriptError +from webkitpy.common.system.outputcapture import OutputCapture # Eventually we will want to write tests which work for both scms. (like update_webkit, changed_files, etc.) # Perhaps through some SCMTest base-class which both SVNTest and GitTest inherit from. @@ -174,6 +176,57 @@ class SVNTestRepository: # Change back to a valid directory so that later calls to os.getcwd() do not fail. os.chdir(detect_scm_system(os.path.dirname(__file__)).checkout_root) + +class StandaloneFunctionsTest(unittest.TestCase): + """This class tests any standalone/top-level functions in the package.""" + def setUp(self): + self.orig_cwd = os.path.abspath(os.getcwd()) + self.orig_abspath = os.path.abspath + + # We capture but ignore the output from stderr to reduce unwanted + # logging. + self.output = OutputCapture() + self.output.capture_output() + + def tearDown(self): + os.chdir(self.orig_cwd) + os.path.abspath = self.orig_abspath + self.output.restore_output() + + def test_find_checkout_root(self): + # Test from inside the tree. + os.chdir(sys.path[0]) + dir = find_checkout_root() + self.assertNotEqual(dir, None) + self.assertTrue(os.path.exists(dir)) + + # Test from outside the tree. + os.chdir(os.path.expanduser("~")) + dir = find_checkout_root() + self.assertNotEqual(dir, None) + self.assertTrue(os.path.exists(dir)) + + # Mock out abspath() to test being not in a checkout at all. + os.path.abspath = lambda x: "/" + self.assertRaises(SystemExit, find_checkout_root) + os.path.abspath = self.orig_abspath + + def test_default_scm(self): + # Test from inside the tree. + os.chdir(sys.path[0]) + scm = default_scm() + self.assertNotEqual(scm, None) + + # Test from outside the tree. + os.chdir(os.path.expanduser("~")) + dir = find_checkout_root() + self.assertNotEqual(dir, None) + + # Mock out abspath() to test being not in a checkout at all. + os.path.abspath = lambda x: "/" + self.assertRaises(SystemExit, default_scm) + os.path.abspath = self.orig_abspath + # For testing the SCM baseclass directly. class SCMClassTests(unittest.TestCase): def setUp(self): diff --git a/WebKitTools/Scripts/webkitpy/common/config/committers.py b/WebKitTools/Scripts/webkitpy/common/config/committers.py index 5ebf18a..7543d69 100644 --- a/WebKitTools/Scripts/webkitpy/common/config/committers.py +++ b/WebKitTools/Scripts/webkitpy/common/config/committers.py @@ -139,6 +139,7 @@ committers_unable_to_review = [ Committer("Krzysztof Kowalczyk", "kkowalczyk@gmail.com"), Committer("Leandro Pereira", ["leandro@profusion.mobi", "leandro@webkit.org"], "acidx"), Committer("Levi Weintraub", "lweintraub@apple.com"), + Committer("Lucas De Marchi", ["lucas.demarchi@profusion.mobi", "demarchi@webkit.org"], "demarchi"), Committer("Luiz Agostini", ["luiz@webkit.org", "luiz.agostini@openbossa.org"], "lca"), Committer("Mads Ager", "ager@chromium.org"), Committer("Marcus Voltis Bulach", "bulach@chromium.org"), @@ -146,7 +147,6 @@ committers_unable_to_review = [ Committer("Matt Perry", "mpcomplete@chromium.org"), Committer("Maxime Britto", ["maxime.britto@gmail.com", "britto@apple.com"]), Committer("Maxime Simon", ["simon.maxime@gmail.com", "maxime.simon@webkit.org"], "maxime.simon"), - Committer("Martin Robinson", ["mrobinson@igalia.com", "mrobinson@webkit.org", "martin.james.robinson@gmail.com"], "mrobinson"), Committer("Michelangelo De Simone", "michelangelo@webkit.org", "michelangelo"), Committer("Mike Belshe", ["mbelshe@chromium.org", "mike@belshe.com"]), Committer("Mike Fenton", ["mifenton@rim.com", "mike.fenton@torchmobile.com"], "mfenton"), @@ -179,7 +179,7 @@ committers_unable_to_review = [ Committer("Yuzo Fujishima", "yuzo@google.com", "yuzo"), Committer("Zhenyao Mo", "zmo@google.com", "zhenyao"), Committer("Zoltan Herczeg", "zherczeg@webkit.org", "zherczeg"), - Committer("Zoltan Horvath", "zoltan@webkit.org", "zoltan"), + Committer("Zoltan Horvath", ["zoltan@webkit.org", "hzoltan@inf.u-szeged.hu", "horvath.zoltan.6@stud.u-szeged.hu"], "zoltan"), ] @@ -200,7 +200,7 @@ reviewers_list = [ Reviewer("Anders Carlsson", ["andersca@apple.com", "acarlsson@apple.com"], "andersca"), Reviewer("Antonio Gomes", "tonikitoo@webkit.org", "tonikitoo"), Reviewer("Antti Koivisto", ["koivisto@iki.fi", "antti@apple.com"], "anttik"), - Reviewer("Ariya Hidayat", ["ariya.hidayat@gmail.com", "ariya@webkit.org"], "ariya"), + Reviewer("Ariya Hidayat", ["ariya@sencha.com", "ariya.hidayat@gmail.com", "ariya@webkit.org"], "ariya"), Reviewer("Beth Dakin", "bdakin@apple.com", "dethbakin"), Reviewer("Brady Eidson", "beidson@apple.com", "bradee-oh"), Reviewer("Cameron Zwarich", ["zwarich@apple.com", "cwzwarich@apple.com", "cwzwarich@webkit.org"]), @@ -225,7 +225,7 @@ reviewers_list = [ Reviewer("Gavin Barraclough", "barraclough@apple.com", "gbarra"), Reviewer("Geoffrey Garen", "ggaren@apple.com", "ggaren"), Reviewer("George Staikos", ["staikos@kde.org", "staikos@webkit.org"]), - Reviewer("Gustavo Noronha Silva", ["gns@gnome.org", "kov@webkit.org"], "kov"), + Reviewer("Gustavo Noronha Silva", ["gns@gnome.org", "kov@webkit.org", "gustavo.noronha@collabora.co.uk"], "kov"), Reviewer("Holger Freyther", ["zecke@selfish.org", "zecke@webkit.org"], "zecke"), Reviewer("Jan Alonzo", ["jmalonzo@gmail.com", "jmalonzo@webkit.org"], "janm"), Reviewer("Jeremy Orlow", "jorlow@chromium.org", "jorlow"), @@ -244,6 +244,7 @@ reviewers_list = [ Reviewer("Laszlo Gombos", "laszlo.1.gombos@nokia.com", "lgombos"), Reviewer("Maciej Stachowiak", "mjs@apple.com", "othermaciej"), Reviewer("Mark Rowe", "mrowe@apple.com", "bdash"), + Reviewer("Martin Robinson", ["mrobinson@igalia.com", "mrobinson@webkit.org", "martin.james.robinson@gmail.com"], "mrobinson"), Reviewer("Nate Chapin", "japhet@chromium.org", "japhet"), Reviewer("Nikolas Zimmermann", ["zimmermann@kde.org", "zimmermann@physik.rwth-aachen.de", "zimmermann@webkit.org"], "wildfox"), Reviewer("Ojan Vafai", "ojan@chromium.org", "ojan"), diff --git a/WebKitTools/Scripts/webkitpy/layout_tests/deduplicate_tests.py b/WebKitTools/Scripts/webkitpy/layout_tests/deduplicate_tests.py new file mode 100644 index 0000000..bb63f5e --- /dev/null +++ b/WebKitTools/Scripts/webkitpy/layout_tests/deduplicate_tests.py @@ -0,0 +1,167 @@ +#!/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. + +"""deduplicate_tests -- lists duplicated between platforms. + +If platform/mac-leopard is missing an expected test output, we fall back on +platform/mac. This means it's possible to grow redundant test outputs, +where we have the same expected data in both a platform directory and another +platform it falls back on. +""" + +import collections +import fnmatch +import os +import subprocess +import sys +import re +import webkitpy.common.system.executive as executive +import webkitpy.common.system.logutils as logutils +import webkitpy.layout_tests.port.factory as port_factory + +_log = logutils.get_logger(__file__) + +_BASE_PLATFORM = 'base' + + +def port_fallbacks(): + """Get the port fallback information. + Returns: + A dictionary mapping platform name to a list of other platforms to fall + back on. All platforms fall back on 'base'. + """ + fallbacks = {_BASE_PLATFORM: []} + for port_name in os.listdir(os.path.join('LayoutTests', 'platform')): + try: + platforms = port_factory.get(port_name).baseline_search_path() + except NotImplementedError: + _log.error("'%s' lacks baseline_search_path(), please fix." % port_name) + fallbacks[port_name] = [_BASE_PLATFORM] + continue + fallbacks[port_name] = [os.path.basename(p) for p in platforms][1:] + fallbacks[port_name].append(_BASE_PLATFORM) + return fallbacks + + +def parse_git_output(git_output, glob_pattern): + """Parses the output of git ls-tree and filters based on glob_pattern. + Args: + git_output: result of git ls-tree -r HEAD LayoutTests. + glob_pattern: a pattern to filter the files. + Returns: + A dictionary mapping (test name, hash of content) => [paths] + """ + hashes = collections.defaultdict(set) + for line in git_output.split('\n'): + if not line: + break + attrs, path = line.strip().split('\t') + if not fnmatch.fnmatch(path, glob_pattern): + continue + path = path[len('LayoutTests/'):] + match = re.match(r'^(platform/.*?/)?(.*)', path) + test = match.group(2) + _, _, hash = attrs.split(' ') + hashes[(test, hash)].add(path) + return hashes + + +def cluster_file_hashes(glob_pattern): + """Get the hashes of all the test expectations in the tree. + We cheat and use git's hashes. + Args: + glob_pattern: a pattern to filter the files. + Returns: + A dictionary mapping (test name, hash of content) => [paths] + """ + + # A map of file hash => set of all files with that hash. + hashes = collections.defaultdict(set) + + # Fill in the map. + cmd = ('git', 'ls-tree', '-r', 'HEAD', 'LayoutTests') + try: + git_output = executive.Executive().run_command(cmd) + except OSError, e: + if e.errno == 2: # No such file or directory. + _log.error("Error: 'No such file' when running git.") + _log.error("This script requires git.") + sys.exit(1) + raise e + return parse_git_output(git_output, glob_pattern) + + +def extract_platforms(paths): + """Extracts the platforms from a list of paths matching ^platform/(.*?)/. + Args: + paths: a list of paths. + Returns: + A dictionary containing all platforms from paths. + """ + platforms = {} + for path in paths: + match = re.match(r'^platform/(.*?)/', path) + if match: + platform = match.group(1) + else: + platform = _BASE_PLATFORM + platforms[platform] = path + return platforms + + +def find_dups(hashes, port_fallbacks): + """Yields info about redundant test expectations. + Args: + hashes: a list of hashes as returned by cluster_file_hashes. + port_fallbacks: a list of fallback information as returned by get_port_fallbacks. + Returns: + a tuple containing (test, platform, fallback, platforms) + """ + for (test, hash), cluster in hashes.items(): + if len(cluster) < 2: + continue # Common case: only one file with that hash. + + # Compute the list of platforms we have this particular hash for. + platforms = extract_platforms(cluster) + if len(platforms) == 1: + continue + + # See if any of the platforms are redundant with each other. + for platform in platforms.keys(): + for fallback in port_fallbacks[platform]: + if fallback in platforms.keys(): + yield test, platform, fallback, platforms[platform] + + +def deduplicate(glob_pattern): + """Traverses LayoutTests and returns information about duplicated files. + Args: + glob pattern to filter the files in LayoutTests. + Returns: + a dictionary containing test, path, platform and fallback. + """ + fallbacks = port_fallbacks() + hashes = cluster_file_hashes(glob_pattern) + return [{'test': test, 'path': path, 'platform': platform, 'fallback': fallback} + for test, platform, fallback, path in find_dups(hashes, fallbacks)] diff --git a/WebKitTools/Scripts/webkitpy/layout_tests/deduplicate_tests_unittest.py b/WebKitTools/Scripts/webkitpy/layout_tests/deduplicate_tests_unittest.py new file mode 100644 index 0000000..66dda32 --- /dev/null +++ b/WebKitTools/Scripts/webkitpy/layout_tests/deduplicate_tests_unittest.py @@ -0,0 +1,147 @@ +#!/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. + +"""Unit tests for deduplicate_tests.py.""" + +import deduplicate_tests +import os +import unittest +import webkitpy.common.checkout.scm as scm + + +class MockExecutive(object): + last_run_command = [] + response = '' + + class Executive(object): + def run_command(self, + args, + cwd=None, + input=None, + error_handler=None, + return_exit_code=False, + return_stderr=True, + decode_output=True): + MockExecutive.last_run_command += [args] + return MockExecutive.response + + +class ListDuplicatesTest(unittest.TestCase): + def setUp(self): + MockExecutive.last_run_command = [] + MockExecutive.response = '' + deduplicate_tests.executive = MockExecutive + self._original_cwd = os.getcwd() + checkout_root = scm.find_checkout_root() + self.assertNotEqual(checkout_root, None) + os.chdir(checkout_root) + + def tearDown(self): + os.chdir(self._original_cwd) + + def test_parse_git_output(self): + git_output = ( + '100644 blob 5053240b3353f6eb39f7cb00259785f16d121df2\tLayoutTests/mac/foo-expected.txt\n' + '100644 blob a004548d107ecc4e1ea08019daf0a14e8634a1ff\tLayoutTests/platform/chromium/foo-expected.txt\n' + '100644 blob d6bb0bc762e3aec5df03b5c04485b2cb3b65ffb1\tLayoutTests/platform/chromium-linux/foo-expected.txt\n' + '100644 blob abcdebc762e3aec5df03b5c04485b2cb3b65ffb1\tLayoutTests/platform/chromium-linux/animage.png\n' + '100644 blob d6bb0bc762e3aec5df03b5c04485b2cb3b65ffb1\tLayoutTests/platform/chromium-win/foo-expected.txt\n' + '100644 blob abcdebc762e3aec5df03b5c04485b2cb3b65ffb1\tLayoutTests/platform/chromium-win/animage.png\n' + '100644 blob 4303df5389ca87cae83dd3236b8dd84e16606517\tLayoutTests/platform/mac/foo-expected.txt\n') + hashes = deduplicate_tests.parse_git_output(git_output, '*') + expected = {('mac/foo-expected.txt', '5053240b3353f6eb39f7cb00259785f16d121df2'): set(['mac/foo-expected.txt']), + ('animage.png', 'abcdebc762e3aec5df03b5c04485b2cb3b65ffb1'): set(['platform/chromium-linux/animage.png', 'platform/chromium-win/animage.png']), + ('foo-expected.txt', '4303df5389ca87cae83dd3236b8dd84e16606517'): set(['platform/mac/foo-expected.txt']), + ('foo-expected.txt', 'd6bb0bc762e3aec5df03b5c04485b2cb3b65ffb1'): set(['platform/chromium-linux/foo-expected.txt', 'platform/chromium-win/foo-expected.txt']), + ('foo-expected.txt', 'a004548d107ecc4e1ea08019daf0a14e8634a1ff'): set(['platform/chromium/foo-expected.txt'])} + self.assertEquals(expected, hashes) + + hashes = deduplicate_tests.parse_git_output(git_output, '*.png') + expected = {('animage.png', 'abcdebc762e3aec5df03b5c04485b2cb3b65ffb1'): set(['platform/chromium-linux/animage.png', 'platform/chromium-win/animage.png'])} + self.assertEquals(expected, hashes) + + def test_extract_platforms(self): + self.assertEquals({'foo': 'platform/foo/bar', + 'zoo': 'platform/zoo/com'}, + deduplicate_tests.extract_platforms(['platform/foo/bar', 'platform/zoo/com'])) + self.assertEquals({'foo': 'platform/foo/bar', + deduplicate_tests._BASE_PLATFORM: 'what/'}, + deduplicate_tests.extract_platforms(['platform/foo/bar', 'what/'])) + + def test_unique(self): + MockExecutive.response = ( + '100644 blob 5053240b3353f6eb39f7cb00259785f16d121df2\tLayoutTests/mac/foo-expected.txt\n' + '100644 blob a004548d107ecc4e1ea08019daf0a14e8634a1ff\tLayoutTests/platform/chromium/foo-expected.txt\n' + '100644 blob abcd0bc762e3aec5df03b5c04485b2cb3b65ffb1\tLayoutTests/platform/chromium-linux/foo-expected.txt\n' + '100644 blob d6bb0bc762e3aec5df03b5c04485b2cb3b65ffb1\tLayoutTests/platform/chromium-win/foo-expected.txt\n' + '100644 blob 4303df5389ca87cae83dd3236b8dd84e16606517\tLayoutTests/platform/mac/foo-expected.txt\n') + result = deduplicate_tests.deduplicate('*') + self.assertEquals(1, len(MockExecutive.last_run_command)) + self.assertEquals(('git', 'ls-tree', '-r', 'HEAD', 'LayoutTests'), MockExecutive.last_run_command[-1]) + self.assertEquals(0, len(result)) + + def test_duplicates(self): + MockExecutive.response = ( + '100644 blob 5053240b3353f6eb39f7cb00259785f16d121df2\tLayoutTests/mac/foo-expected.txt\n' + '100644 blob a004548d107ecc4e1ea08019daf0a14e8634a1ff\tLayoutTests/platform/chromium/foo-expected.txt\n' + '100644 blob d6bb0bc762e3aec5df03b5c04485b2cb3b65ffb1\tLayoutTests/platform/chromium-linux/foo-expected.txt\n' + '100644 blob abcdebc762e3aec5df03b5c04485b2cb3b65ffb1\tLayoutTests/platform/chromium-linux/animage.png\n' + '100644 blob d6bb0bc762e3aec5df03b5c04485b2cb3b65ffb1\tLayoutTests/platform/chromium-win/foo-expected.txt\n' + '100644 blob abcdebc762e3aec5df03b5c04485b2cb3b65ffb1\tLayoutTests/platform/chromium-win/animage.png\n' + '100644 blob 4303df5389ca87cae83dd3236b8dd84e16606517\tLayoutTests/platform/mac/foo-expected.txt\n') + + result = deduplicate_tests.deduplicate('*') + self.assertEquals(1, len(MockExecutive.last_run_command)) + self.assertEquals(('git', 'ls-tree', '-r', 'HEAD', 'LayoutTests'), MockExecutive.last_run_command[-1]) + self.assertEquals(2, len(result)) + self.assertEquals({'test': 'animage.png', + 'path': 'platform/chromium-linux/animage.png', + 'fallback': 'chromium-win', + 'platform': 'chromium-linux'}, + result[0]) + self.assertEquals({'test': 'foo-expected.txt', + 'path': 'platform/chromium-linux/foo-expected.txt', + 'fallback': 'chromium-win', + 'platform': 'chromium-linux'}, + result[1]) + + result = deduplicate_tests.deduplicate('*.txt') + self.assertEquals(2, len(MockExecutive.last_run_command)) + self.assertEquals(('git', 'ls-tree', '-r', 'HEAD', 'LayoutTests'), MockExecutive.last_run_command[-1]) + self.assertEquals(1, len(result)) + self.assertEquals({'test': 'foo-expected.txt', + 'path': 'platform/chromium-linux/foo-expected.txt', + 'fallback': 'chromium-win', + 'platform': 'chromium-linux'}, + result[0]) + + result = deduplicate_tests.deduplicate('*.png') + self.assertEquals(3, len(MockExecutive.last_run_command)) + self.assertEquals(('git', 'ls-tree', '-r', 'HEAD', 'LayoutTests'), MockExecutive.last_run_command[-1]) + self.assertEquals(1, len(result)) + self.assertEquals({'test': 'animage.png', + 'path': 'platform/chromium-linux/animage.png', + 'fallback': 'chromium-win', + 'platform': 'chromium-linux'}, + result[0]) diff --git a/WebKitTools/Scripts/webkitpy/layout_tests/layout_package/dump_render_tree_thread.py b/WebKitTools/Scripts/webkitpy/layout_tests/layout_package/dump_render_tree_thread.py index 6364511..6343400 100644 --- a/WebKitTools/Scripts/webkitpy/layout_tests/layout_package/dump_render_tree_thread.py +++ b/WebKitTools/Scripts/webkitpy/layout_tests/layout_package/dump_render_tree_thread.py @@ -54,9 +54,9 @@ _log = logging.getLogger("webkitpy.layout_tests.layout_package." "dump_render_tree_thread") -def process_output(port, test_info, test_types, test_args, configuration, - output_dir, crash, timeout, test_run_time, actual_checksum, - output, error): +def _process_output(port, test_info, test_types, test_args, configuration, + output_dir, crash, timeout, test_run_time, actual_checksum, + output, error): """Receives the output from a DumpRenderTree process, subjects it to a number of tests, and returns a list of failure types the test produced. @@ -118,6 +118,21 @@ def process_output(port, test_info, test_types, test_args, configuration, 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 + + class TestResult(object): def __init__(self, filename, failures, test_run_time, @@ -162,7 +177,7 @@ class SingleTestThread(threading.Thread): driver.run_test(test_info.uri.strip(), test_info.timeout, test_info.image_hash()) end = time.time() - self._test_result = process_output(self._port, + self._test_result = _process_output(self._port, test_info, self._test_types, self._test_args, self._configuration, self._output_dir, crash, timeout, end - start, actual_checksum, output, error) @@ -172,8 +187,42 @@ class SingleTestThread(threading.Thread): return self._test_result -class TestShellThread(threading.Thread): +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): def __init__(self, port, filename_list_queue, result_queue, test_types, test_args, image_path, shell_args, options): """Initialize all the local state for this DumpRenderTree thread. @@ -192,7 +241,7 @@ class TestShellThread(threading.Thread): command-line options should match those expected by run_webkit_tests; they are typically passed via the run_webkit_tests.TestRunner class.""" - threading.Thread.__init__(self) + WatchableThread.__init__(self) self._port = port self._filename_list_queue = filename_list_queue self._result_queue = result_queue @@ -203,8 +252,6 @@ class TestShellThread(threading.Thread): self._image_path = image_path self._shell_args = shell_args self._options = options - self._canceled = False - self._exception_info = None self._directory_timing_stats = {} self._test_results = [] self._num_tests = 0 @@ -231,17 +278,6 @@ class TestShellThread(threading.Thread): """ return self._test_results - def cancel(self): - """Set a flag telling this thread to quit.""" - self._canceled = True - - def get_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 get_total_time(self): return max(self._stop_time - self._start_time, 0.0) @@ -251,6 +287,7 @@ class TestShellThread(threading.Thread): def run(self): """Delegate main work to a helper method and watch for uncaught exceptions.""" + self._thread_id = thread.get_ident() self._start_time = time.time() self._num_tests = 0 try: @@ -384,10 +421,10 @@ class TestShellThread(threading.Thread): worker.start() - # 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. - worker.join(int(test_info.timeout) * 3.0 / 1000.0) + thread_timeout = _milliseconds_to_seconds( + _pad_timeout(test_info.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 @@ -433,11 +470,16 @@ class TestShellThread(threading.Thread): not self._options.pixel_tests)): image_hash = "" start = time.time() + + thread_timeout = _milliseconds_to_seconds( + _pad_timeout(test_info.timeout)) + self._next_timeout = start + thread_timeout + crash, timeout, actual_checksum, output, error = \ self._driver.run_test(test_info.uri, test_info.timeout, image_hash) end = time.time() - result = process_output(self._port, test_info, self._test_types, + result = _process_output(self._port, test_info, self._test_types, self._test_args, self._options.configuration, self._options.results_directory, crash, timeout, end - start, actual_checksum, diff --git a/WebKitTools/Scripts/webkitpy/layout_tests/layout_package/json_layout_results_generator.py b/WebKitTools/Scripts/webkitpy/layout_tests/layout_package/json_layout_results_generator.py index 6c36c93..c6c3066 100644 --- a/WebKitTools/Scripts/webkitpy/layout_tests/layout_package/json_layout_results_generator.py +++ b/WebKitTools/Scripts/webkitpy/layout_tests/layout_package/json_layout_results_generator.py @@ -57,7 +57,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): + generate_incremental_results=False, test_results_server=None): """Modifies the results.json file. Grabs it off the archive directory if it is not found locally. @@ -68,7 +68,7 @@ class JSONLayoutResultsGenerator(json_results_generator.JSONResultsGeneratorBase super(JSONLayoutResultsGenerator, self).__init__( builder_name, build_name, build_number, results_file_base_path, builder_base_url, {}, port.test_repository_paths(), - generate_incremental_results) + generate_incremental_results, test_results_server) self._port = port self._expectations = expectations diff --git a/WebKitTools/Scripts/webkitpy/layout_tests/layout_package/json_results_generator.py b/WebKitTools/Scripts/webkitpy/layout_tests/layout_package/json_results_generator.py index e746bc0..15eceee 100644 --- a/WebKitTools/Scripts/webkitpy/layout_tests/layout_package/json_results_generator.py +++ b/WebKitTools/Scripts/webkitpy/layout_tests/layout_package/json_results_generator.py @@ -84,10 +84,14 @@ class JSONResultsGeneratorBase(object): RESULTS_FILENAME = "results.json" INCREMENTAL_RESULTS_FILENAME = "incremental_results.json" + URL_FOR_TEST_LIST_JSON = \ + "http://%s/testfile?builder=%s&name=%s&testlistjson=1" + def __init__(self, builder_name, build_name, build_number, results_file_base_path, builder_base_url, test_results_map, svn_repositories=None, - generate_incremental_results=False): + generate_incremental_results=False, + test_results_server=None): """Modifies the results.json file. Grabs it off the archive directory if it is not found locally. @@ -103,6 +107,9 @@ 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. """ self._builder_name = builder_name self._build_name = build_name @@ -121,6 +128,8 @@ class JSONResultsGeneratorBase(object): if not self._svn_repositories: self._svn_repositories = {} + self._test_results_server = test_results_server + self._json = None self._archived_results = None @@ -144,25 +153,24 @@ class JSONResultsGeneratorBase(object): def get_json(self, incremental=False): """Gets the results for the results.json file.""" - if incremental: - results_json = {} - else: + results_json = {} + if not incremental: if self._json: return self._json - if not self._archived_results: - self._archived_results, 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 - # bot. - _log.error("Archive directory is inaccessible. Not " - "modifying or clobbering the results.json " - "file: " + str(error)) - return None + if self._archived_results: + results_json = self._archived_results - results_json = self._archived_results + if not results_json: + results_json, error = self._get_archived_json_results(incremental) + 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 + # bot. + _log.error("Archive directory is inaccessible. Not " + "modifying or clobbering the results.json " + "file: " + str(error)) + return None builder_name = self._builder_name if results_json and builder_name not in results_json: @@ -186,7 +194,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) + self._insert_test_time_and_result(test, tests, incremental) return results_json @@ -253,24 +261,40 @@ class JSONResultsGeneratorBase(object): return "" return "" - def _get_archived_json_results(self): + 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 + 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. """ results_json = {} old_results = None error = None - if os.path.exists(self._results_file_path): + if os.path.exists(self._results_file_path) and not for_incremental: with codecs.open(self._results_file_path, "r", "utf-8") as file: old_results = file.read() - elif self._builder_base_url: - # 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) + 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)) + 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) try: results_file = urllib2.urlopen(results_file_url) @@ -387,7 +411,7 @@ class JSONResultsGeneratorBase(object): int(time.time()), self.TIME) - def _insert_test_time_and_result(self, test_name, tests): + def _insert_test_time_and_result(self, test_name, tests, incremental=False): """ Insert a test item with its results to the given tests dictionary. Args: @@ -401,9 +425,20 @@ class JSONResultsGeneratorBase(object): tests[test_name] = self._create_results_and_times_json() thisTest = tests[test_name] - self._insert_item_run_length_encoded(result, thisTest[self.RESULTS]) - self._insert_item_run_length_encoded(time, thisTest[self.TIMES]) - self._normalize_results_json(thisTest, test_name, tests) + if self.RESULTS in thisTest: + self._insert_item_run_length_encoded(result, thisTest[self.RESULTS]) + else: + thisTest[self.RESULTS] = [[1, result]] + + if self.TIMES in thisTest: + self._insert_item_run_length_encoded(time, thisTest[self.TIMES]) + 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 diff --git a/WebKitTools/Scripts/webkitpy/layout_tests/layout_package/printing.py b/WebKitTools/Scripts/webkitpy/layout_tests/layout_package/printing.py index f838a7b..81cdc9b 100644 --- a/WebKitTools/Scripts/webkitpy/layout_tests/layout_package/printing.py +++ b/WebKitTools/Scripts/webkitpy/layout_tests/layout_package/printing.py @@ -123,12 +123,6 @@ def print_options(): help="show detailed help on controlling print output"), optparse.make_option("-v", "--verbose", action="store_true", default=False, help="include debug-level logging"), - - # FIXME: we should remove this; it's pretty much obsolete with the - # --print trace-everything option. - optparse.make_option("--sources", action="store_true", - help=("show expected result file path for each test " - "(implies --verbose)")), ] diff --git a/WebKitTools/Scripts/webkitpy/layout_tests/layout_package/test_expectations.py b/WebKitTools/Scripts/webkitpy/layout_tests/layout_package/test_expectations.py index 38223dd..e154932 100644 --- a/WebKitTools/Scripts/webkitpy/layout_tests/layout_package/test_expectations.py +++ b/WebKitTools/Scripts/webkitpy/layout_tests/layout_package/test_expectations.py @@ -460,6 +460,9 @@ class TestExpectationsFile: return ExpectationsJsonEncoder(separators=(',', ':')).encode( self._all_expectations) + def get_non_fatal_errors(self): + return self._non_fatal_errors + def contains(self, test): return test in self._test_to_expectations diff --git a/WebKitTools/Scripts/webkitpy/layout_tests/layout_package/test_failures.py b/WebKitTools/Scripts/webkitpy/layout_tests/layout_package/test_failures.py index 60bdbca..3be9240 100644 --- a/WebKitTools/Scripts/webkitpy/layout_tests/layout_package/test_failures.py +++ b/WebKitTools/Scripts/webkitpy/layout_tests/layout_package/test_failures.py @@ -250,15 +250,6 @@ class FailureImageHashMismatch(FailureWithType): return "Image mismatch" -class FailureFuzzyFailure(FailureWithType): - """Image hashes didn't match.""" - OUT_FILENAMES = ["-actual.png", "-expected.png"] - - @staticmethod - def message(): - return "Fuzzy image match also failed" - - class FailureImageHashIncorrect(FailureWithType): """Actual result hash is incorrect.""" # Chrome doesn't know to display a .checksum file as text, so don't bother diff --git a/WebKitTools/Scripts/webkitpy/layout_tests/port/chromium_win.py b/WebKitTools/Scripts/webkitpy/layout_tests/port/chromium_win.py index 8072bc0..e9a81e7 100644 --- a/WebKitTools/Scripts/webkitpy/layout_tests/port/chromium_win.py +++ b/WebKitTools/Scripts/webkitpy/layout_tests/port/chromium_win.py @@ -69,9 +69,9 @@ class ChromiumWinPort(chromium.ChromiumPort): def baseline_search_path(self): port_names = [] - if self._name == 'chromium-win-xp': + if self._name.endswith('-win-xp'): port_names.append("chromium-win-xp") - if self._name in ('chromium-win-xp', 'chromium-win-vista'): + if self._name.endswith('-win-xp') or self._name.endswith('-win-vista'): port_names.append("chromium-win-vista") # FIXME: This may need to include mac-snowleopard like win.py. port_names.extend(["chromium-win", "chromium", "win", "mac"]) diff --git a/WebKitTools/Scripts/webkitpy/layout_tests/port/factory.py b/WebKitTools/Scripts/webkitpy/layout_tests/port/factory.py index 95b90da..258bf33 100644 --- a/WebKitTools/Scripts/webkitpy/layout_tests/port/factory.py +++ b/WebKitTools/Scripts/webkitpy/layout_tests/port/factory.py @@ -83,5 +83,8 @@ def get(port_name=None, options=None): elif port_to_use.startswith('chromium-win'): import chromium_win return chromium_win.ChromiumWinPort(port_name, options) + elif port_to_use.startswith('google-chrome'): + import google_chrome + return google_chrome.GetGoogleChromePort(port_name, options) raise NotImplementedError('unsupported port: %s' % port_to_use) diff --git a/WebKitTools/Scripts/webkitpy/layout_tests/port/google_chrome.py b/WebKitTools/Scripts/webkitpy/layout_tests/port/google_chrome.py new file mode 100644 index 0000000..1ea053b --- /dev/null +++ b/WebKitTools/Scripts/webkitpy/layout_tests/port/google_chrome.py @@ -0,0 +1,74 @@ +#!/usr/bin/env python +# Copyright (C) 2010 Google Inc. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following disclaimer +# in the documentation and/or other materials provided with the +# distribution. + +# 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 GetGoogleChromePort(port_name, options): + """Some tests have slightly different results when compiled as Google + Chrome vs Chromium. In those cases, we prepend an additional directory to + to the baseline paths.""" + if port_name == 'google-chrome-linux32': + import chromium_linux + + class GoogleChromeLinux32Port(chromium_linux.ChromiumLinuxPort): + def baseline_search_path(self): + paths = chromium_linux.ChromiumLinuxPort.baseline_search_path( + self) + paths.insert(0, self._webkit_baseline_path(self._name)) + return paths + return GoogleChromeLinux32Port(port_name, options) + elif port_name == 'google-chrome-linux64': + import chromium_linux + + class GoogleChromeLinux64Port(chromium_linux.ChromiumLinuxPort): + def baseline_search_path(self): + paths = chromium_linux.ChromiumLinuxPort.baseline_search_path( + self) + paths.insert(0, self._webkit_baseline_path(self._name)) + return paths + return GoogleChromeLinux64Port(port_name, options) + elif port_name.startswith('google-chrome-mac'): + import chromium_mac + + class GoogleChromeMacPort(chromium_mac.ChromiumMacPort): + def baseline_search_path(self): + paths = chromium_mac.ChromiumMacPort.baseline_search_path( + self) + paths.insert(0, self._webkit_baseline_path( + 'google-chrome-mac')) + return paths + return GoogleChromeMacPort(port_name, options) + elif port_name.startswith('google-chrome-win'): + import chromium_win + + class GoogleChromeWinPort(chromium_win.ChromiumWinPort): + def baseline_search_path(self): + paths = chromium_win.ChromiumWinPort.baseline_search_path( + self) + paths.insert(0, self._webkit_baseline_path( + 'google-chrome-win')) + return paths + return GoogleChromeWinPort(port_name, options) + raise NotImplementedError('unsupported port: %s' % port_name) diff --git a/WebKitTools/Scripts/webkitpy/layout_tests/port/google_chrome_unittest.py b/WebKitTools/Scripts/webkitpy/layout_tests/port/google_chrome_unittest.py new file mode 100644 index 0000000..a2d7056 --- /dev/null +++ b/WebKitTools/Scripts/webkitpy/layout_tests/port/google_chrome_unittest.py @@ -0,0 +1,46 @@ +#!/usr/bin/env python +# Copyright (C) 2010 Google Inc. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following disclaimer +# in the documentation and/or other materials provided with the +# distribution. + +# 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 +import unittest +import google_chrome + + +class GetGoogleChromePortTest(unittest.TestCase): + def test_get_google_chrome_port(self): + test_ports = ('google-chrome-linux32', 'google-chrome-linux64', + 'google-chrome-mac', 'google-chrome-win') + for port in test_ports: + self._verify_baseline_path(port, port) + + self._verify_baseline_path('google-chrome-mac', 'google-chrome-mac-leopard') + self._verify_baseline_path('google-chrome-win', 'google-chrome-win-xp') + self._verify_baseline_path('google-chrome-win', 'google-chrome-win-vista') + + def _verify_baseline_path(self, expected_path, port_name): + port = google_chrome.GetGoogleChromePort(port_name, None) + path = port.baseline_search_path()[0] + self.assertEqual(expected_path, os.path.split(path)[1]) diff --git a/WebKitTools/Scripts/webkitpy/layout_tests/port/test.py b/WebKitTools/Scripts/webkitpy/layout_tests/port/test.py index 6eef54e..9c9ab0a 100644 --- a/WebKitTools/Scripts/webkitpy/layout_tests/port/test.py +++ b/WebKitTools/Scripts/webkitpy/layout_tests/port/test.py @@ -124,6 +124,9 @@ class TestPort(base.Port): def test_platform_names(self): return self.test_base_platform_names() + def test_platform_name_to_name(self, test_platform_name): + return test_platform_name + def version(): return '' diff --git a/WebKitTools/Scripts/webkitpy/layout_tests/rebaseline_chromium_webkit_tests.py b/WebKitTools/Scripts/webkitpy/layout_tests/rebaseline_chromium_webkit_tests.py index fa4df9b..92f1032 100644 --- a/WebKitTools/Scripts/webkitpy/layout_tests/rebaseline_chromium_webkit_tests.py +++ b/WebKitTools/Scripts/webkitpy/layout_tests/rebaseline_chromium_webkit_tests.py @@ -59,7 +59,6 @@ import webbrowser import zipfile from webkitpy.common.system.executive import run_command, ScriptError -from webkitpy.common.checkout.scm import detect_scm_system import webkitpy.common.checkout.scm as scm import port @@ -240,7 +239,7 @@ class Rebaseliner(object): self._platform, False, False) - self._scm = detect_scm_system(os.getcwd()) + self._scm = scm.default_scm() def run(self, backup): """Run rebaseline process.""" diff --git a/WebKitTools/Scripts/webkitpy/layout_tests/rebaseline_chromium_webkit_tests_unittest.py b/WebKitTools/Scripts/webkitpy/layout_tests/rebaseline_chromium_webkit_tests_unittest.py index fa03238..121b64e 100644 --- a/WebKitTools/Scripts/webkitpy/layout_tests/rebaseline_chromium_webkit_tests_unittest.py +++ b/WebKitTools/Scripts/webkitpy/layout_tests/rebaseline_chromium_webkit_tests_unittest.py @@ -84,5 +84,19 @@ class TestGetHostPortObject(unittest.TestCase): port.get = old_get +class TestRebaseliner(unittest.TestCase): + + def test_noop(self): + # this method tests that was can at least instantiate an object, even + # if there is nothing to do. + options = MockOptions() + host_port_obj = port.get('test', options) + target_options = options + target_port_obj = port.get('test', target_options) + platform = 'test' + rebaseliner = rebaseline_chromium_webkit_tests.Rebaseliner( + host_port_obj, target_port_obj, platform, options) + self.assertNotEqual(rebaseliner, None) + if __name__ == '__main__': unittest.main() diff --git a/WebKitTools/Scripts/webkitpy/layout_tests/run_webkit_tests.py b/WebKitTools/Scripts/webkitpy/layout_tests/run_webkit_tests.py index 490ac3c..b26bc6c 100755 --- a/WebKitTools/Scripts/webkitpy/layout_tests/run_webkit_tests.py +++ b/WebKitTools/Scripts/webkitpy/layout_tests/run_webkit_tests.py @@ -53,6 +53,7 @@ import logging import math import optparse import os +import pdb import platform import Queue import random @@ -70,7 +71,6 @@ from layout_package import test_expectations from layout_package import test_failures from layout_package import test_files from layout_package import test_results_uploader -from test_types import fuzzy_image_diff from test_types import image_diff from test_types import text_diff from test_types import test_type_base @@ -578,8 +578,6 @@ class TestRunner: test_args.new_baseline = self._options.new_baseline test_args.reset_results = self._options.reset_results - test_args.show_sources = self._options.sources - if self._options.startup_dialog: shell_args.append('--testshell-startup-dialog') @@ -629,35 +627,12 @@ class TestRunner: """Returns whether we should run all the tests in the main thread.""" return int(self._options.child_processes) == 1 - def _dump_thread_states(self): - for thread_id, stack in sys._current_frames().items(): - # FIXME: Python 2.6 has thread.ident which we could - # use to map from thread_id back to thread.name - print "\n# Thread: %d" % thread_id - for filename, lineno, name, line in traceback.extract_stack(stack): - print 'File: "%s", line %d, in %s' % (filename, lineno, name) - if line: - print " %s" % (line.strip()) - - def _dump_thread_states_if_necessary(self): - # HACK: Dump thread states every minute to figure out what's - # hanging on the bots. - if not self._options.verbose: - return - dump_threads_every = 60 # Dump every minute - if not self._last_thread_dump: - self._last_thread_dump = time.time() - time_since_last_dump = time.time() - self._last_thread_dump - if time_since_last_dump > dump_threads_every: - self._dump_thread_states() - self._last_thread_dump = time.time() - def _run_tests(self, file_list, result_summary): """Runs the tests in the file_list. - Return: A tuple (failures, thread_timings, test_timings, + Return: A tuple (keyboard_interrupted, thread_timings, test_timings, individual_test_timings) - failures is a map from test to list of failure types + 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 @@ -676,44 +651,55 @@ class TestRunner: result_summary) self._printer.print_update("Starting testing ...") - # Wait for the threads to finish and collect test failures. - failures = {} - test_timings = {} - individual_test_timings = [] - thread_timings = [] + keyboard_interrupted = self._wait_for_threads_to_finish(threads, + result_summary) + (thread_timings, test_timings, individual_test_timings) = \ + self._collect_timing_info(threads) + + return (keyboard_interrupted, thread_timings, test_timings, + individual_test_timings) + + def _wait_for_threads_to_finish(self, threads, result_summary): keyboard_interrupted = False try: # Loop through all the threads waiting for them to finish. - for thread in threads: - # FIXME: We'll end up waiting on the first thread the whole - # time. That means we won't notice exceptions on other - # threads until the first one exits. - # We should instead while True: in the outer loop - # and then loop through threads joining and checking - # isAlive and get_exception_info. Exiting on any exception. - while thread.isAlive(): - # Wake the main thread every 0.1 seconds so we - # can call update_summary in a timely fashion. - thread.join(0.1) - # HACK: Used for debugging threads on the bots. - self._dump_thread_states_if_necessary() - self.update_summary(result_summary) + some_thread_is_alive = True + while some_thread_is_alive: + some_thread_is_alive = False + t = time.time() + for thread in threads: + exception_info = thread.exception_info() + if exception_info is not None: + # Re-raise the thread's exception here to make it + # clear that testing was aborted. Otherwise, + # the tests that did not run would be assumed + # to have passed. + raise (exception_info[0], exception_info[1], + exception_info[2]) + + if thread.isAlive(): + some_thread_is_alive = True + next_timeout = thread.next_timeout() + if (next_timeout and t > next_timeout): + _log_wedged_thread(thread) + thread.clear_next_timeout() + + self.update_summary(result_summary) + + if some_thread_is_alive: + time.sleep(0.1) except KeyboardInterrupt: keyboard_interrupted = True for thread in threads: thread.cancel() - if not keyboard_interrupted: - for thread in threads: - # Check whether a thread died before normal completion. - exception_info = thread.get_exception_info() - if exception_info is not None: - # Re-raise the thread's exception here to make it clear - # something went wrong. Otherwise, the tests that did not - # run would be assumed to have passed. - raise (exception_info[0], exception_info[1], - exception_info[2]) + return keyboard_interrupted + + def _collect_timing_info(self, threads): + test_timings = {} + individual_test_timings = [] + thread_timings = [] for thread in threads: thread_timings.append({'name': thread.getName(), @@ -721,8 +707,8 @@ class TestRunner: 'total_time': thread.get_total_time()}) test_timings.update(thread.get_directory_timing_stats()) individual_test_timings.extend(thread.get_test_results()) - return (keyboard_interrupted, thread_timings, test_timings, - individual_test_timings) + + return (thread_timings, test_timings, individual_test_timings) def needs_http(self): """Returns whether the test runner needs an HTTP server.""" @@ -890,7 +876,8 @@ 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) + not self._options.upload_full_results, + self._options.test_results_server) _log.debug("Finished writing JSON files.") @@ -1440,8 +1427,6 @@ def run(port_obj, options, args, regular_output=sys.stderr, test_runner.add_test_type(text_diff.TestTextDiff) if options.pixel_tests: test_runner.add_test_type(image_diff.ImageDiff) - if options.fuzzy_pixel_tests: - test_runner.add_test_type(fuzzy_image_diff.FuzzyImageDiff) num_unexpected_results = test_runner.run(result_summary) @@ -1524,9 +1509,6 @@ def parse_args(args=None): dest="pixel_tests", help="Enable pixel-to-pixel PNG comparisons"), optparse.make_option("--no-pixel-tests", action="store_false", dest="pixel_tests", help="Disable pixel-to-pixel PNG comparisons"), - optparse.make_option("--fuzzy-pixel-tests", action="store_true", - default=False, - help="Also use fuzzy matching to compare pixel test outputs."), # old-run-webkit-tests allows a specific tolerance: --tolerance t # Ignore image differences less than this percentage (default: 0.1) optparse.make_option("--results-directory", @@ -1674,12 +1656,38 @@ def parse_args(args=None): option_parser = optparse.OptionParser(option_list=option_list) options, args = option_parser.parse_args(args) - if options.sources: - options.verbose = True return options, args +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()) + + +def _log_wedged_thread(thread): + """Log information about the given thread state.""" + id = thread.id() + stack = _find_thread_stack(id) + assert(stack is not None) + _log.error("") + _log.error("thread %s (%d) is wedged" % (thread.getName(), id)) + _log_stack(stack) + _log.error("") + + def main(): options, args = parse_args() port_obj = port.get(options.platform, options) diff --git a/WebKitTools/Scripts/webkitpy/layout_tests/run_webkit_tests_unittest.py b/WebKitTools/Scripts/webkitpy/layout_tests/run_webkit_tests_unittest.py index 1c751d6..e1b3746 100644 --- a/WebKitTools/Scripts/webkitpy/layout_tests/run_webkit_tests_unittest.py +++ b/WebKitTools/Scripts/webkitpy/layout_tests/run_webkit_tests_unittest.py @@ -30,13 +30,20 @@ """Unit tests for run_webkit_tests.""" import codecs +import logging import os +import pdb +import Queue import sys +import thread +import time +import threading import unittest from webkitpy.common import array_stream from webkitpy.layout_tests import port from webkitpy.layout_tests import run_webkit_tests +from webkitpy.layout_tests.layout_package import dump_render_tree_thread from webkitpy.thirdparty.mock import Mock @@ -92,6 +99,7 @@ class MainTest(unittest.TestCase): self.assertEqual(buildbot_output.get(), []) + def _mocked_open(original_open, file_list): def _wrapper(name, mode, encoding): if name.find("-expected.") != -1 and mode == "w": @@ -191,5 +199,110 @@ class DryrunTest(unittest.TestCase): 'fast/html'])) +class TestThread(dump_render_tree_thread.WatchableThread): + def __init__(self, started_queue, stopping_queue): + dump_render_tree_thread.WatchableThread.__init__(self) + self._started_queue = started_queue + self._stopping_queue = stopping_queue + self._timeout = False + self._timeout_queue = Queue.Queue() + + def run(self): + self._thread_id = thread.get_ident() + try: + self._started_queue.put('') + msg = self._stopping_queue.get() + if msg == 'KeyboardInterrupt': + raise KeyboardInterrupt + elif msg == 'Exception': + raise ValueError() + elif msg == 'Timeout': + self._timeout = True + self._timeout_queue.get() + except: + self._exception_info = sys.exc_info() + + def next_timeout(self): + if self._timeout: + self._timeout_queue.put('done') + return time.time() - 10 + return time.time() + + +class TestHandler(logging.Handler): + def __init__(self, astream): + logging.Handler.__init__(self) + self._stream = astream + + def emit(self, record): + self._stream.write(self.format(record)) + + +class WaitForThreadsToFinishTest(unittest.TestCase): + class MockTestRunner(run_webkit_tests.TestRunner): + def __init__(self): + pass + + def __del__(self): + pass + + def update_summary(self, result_summary): + pass + + def run_one_thread(self, msg): + runner = self.MockTestRunner() + starting_queue = Queue.Queue() + stopping_queue = Queue.Queue() + child_thread = TestThread(starting_queue, stopping_queue) + child_thread.start() + started_msg = starting_queue.get() + stopping_queue.put(msg) + threads = [child_thread] + return runner._wait_for_threads_to_finish(threads, None) + + def test_basic(self): + interrupted = self.run_one_thread('') + self.assertFalse(interrupted) + + def test_interrupt(self): + interrupted = self.run_one_thread('KeyboardInterrupt') + self.assertTrue(interrupted) + + def test_timeout(self): + interrupted = self.run_one_thread('Timeout') + self.assertFalse(interrupted) + + def test_exception(self): + self.assertRaises(ValueError, self.run_one_thread, 'Exception') + + +class StandaloneFunctionsTest(unittest.TestCase): + def test_log_wedged_thread(self): + logger = run_webkit_tests._log + astream = array_stream.ArrayStream() + handler = TestHandler(astream) + logger.addHandler(handler) + + starting_queue = Queue.Queue() + stopping_queue = Queue.Queue() + child_thread = TestThread(starting_queue, stopping_queue) + child_thread.start() + msg = starting_queue.get() + + run_webkit_tests._log_wedged_thread(child_thread) + stopping_queue.put('') + child_thread.join(timeout=1.0) + + self.assertFalse(astream.empty()) + self.assertFalse(child_thread.isAlive()) + + def test_find_thread_stack(self): + id, stack = sys._current_frames().items()[0] + found_stack = run_webkit_tests._find_thread_stack(id) + self.assertNotEqual(found_stack, None) + + found_stack = run_webkit_tests._find_thread_stack(0) + self.assertEqual(found_stack, None) + if __name__ == '__main__': unittest.main() diff --git a/WebKitTools/Scripts/webkitpy/layout_tests/test_types/fuzzy_image_diff.py b/WebKitTools/Scripts/webkitpy/layout_tests/test_types/fuzzy_image_diff.py deleted file mode 100644 index 64dfb20..0000000 --- a/WebKitTools/Scripts/webkitpy/layout_tests/test_types/fuzzy_image_diff.py +++ /dev/null @@ -1,71 +0,0 @@ -#!/usr/bin/env python -# Copyright (C) 2010 Google Inc. All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are -# met: -# -# * Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# * Redistributions in binary form must reproduce the above -# copyright notice, this list of conditions and the following disclaimer -# in the documentation and/or other materials provided with the -# distribution. -# * Neither the name of Google Inc. nor the names of its -# contributors may be used to endorse or promote products derived from -# this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -"""Compares the image output of a test to the expected image output using -fuzzy matching. -""" - -import errno -import logging -import os -import shutil - -from webkitpy.layout_tests.layout_package import test_failures -from webkitpy.layout_tests.test_types import test_type_base - -_log = logging.getLogger("webkitpy.layout_tests.test_types.fuzzy_image_diff") - - -class FuzzyImageDiff(test_type_base.TestTypeBase): - - def compare_output(self, filename, output, test_args, configuration): - """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 test_args.hash is None: - return failures - - expected_png_file = self._port.expected_filename(filename, '.png') - - if test_args.show_sources: - _log.debug('Using %s' % expected_png_file) - - # Also report a missing expected PNG file. - if not os.path.isfile(expected_png_file): - failures.append(test_failures.FailureMissingImage(self)) - - # Run the fuzzymatcher - r = self._port.fuzzy_diff(test_args.png_path, expected_png_file) - if r != 0: - failures.append(test_failures.FailureFuzzyFailure(self)) - - return failures diff --git a/WebKitTools/Scripts/webkitpy/layout_tests/test_types/image_diff.py b/WebKitTools/Scripts/webkitpy/layout_tests/test_types/image_diff.py index 65f8f3a..c9f4107 100644 --- a/WebKitTools/Scripts/webkitpy/layout_tests/test_types/image_diff.py +++ b/WebKitTools/Scripts/webkitpy/layout_tests/test_types/image_diff.py @@ -136,7 +136,7 @@ class ImageDiff(test_type_base.TestTypeBase): # If we're generating a new baseline, we pass. if test_args.new_baseline or test_args.reset_results: self._save_baseline_files(filename, test_args.png_path, - test_args.hash, test_args.new_baseline) + test_args.hash, test_args.new_baseline) return failures # Compare hashes. @@ -144,10 +144,6 @@ class ImageDiff(test_type_base.TestTypeBase): '.checksum') expected_png_file = self._port.expected_filename(filename, '.png') - if test_args.show_sources: - _log.debug('Using %s' % expected_hash_file) - _log.debug('Using %s' % expected_png_file) - # FIXME: We repeat this pattern often, we should share code. try: with codecs.open(expected_hash_file, "r", "ascii") as file: diff --git a/WebKitTools/Scripts/webkitpy/layout_tests/test_types/test_type_base.py b/WebKitTools/Scripts/webkitpy/layout_tests/test_types/test_type_base.py index 8db2e3d..dd44642 100644 --- a/WebKitTools/Scripts/webkitpy/layout_tests/test_types/test_type_base.py +++ b/WebKitTools/Scripts/webkitpy/layout_tests/test_types/test_type_base.py @@ -58,9 +58,6 @@ class TestArguments(object): # Whether to use wdiff to generate by-word diffs. wdiff = False - # Whether to report the locations of the expected result files used. - show_sources = False - # Python bug workaround. See the wdiff code in WriteOutputFiles for an # explanation. _wdiff_available = True diff --git a/WebKitTools/Scripts/webkitpy/layout_tests/test_types/text_diff.py b/WebKitTools/Scripts/webkitpy/layout_tests/test_types/text_diff.py index 18f74b8..d06ec8d 100644 --- a/WebKitTools/Scripts/webkitpy/layout_tests/test_types/text_diff.py +++ b/WebKitTools/Scripts/webkitpy/layout_tests/test_types/text_diff.py @@ -48,25 +48,22 @@ _log = logging.getLogger("webkitpy.layout_tests.test_types.text_diff") class TestTextDiff(test_type_base.TestTypeBase): - def get_normalized_output_text(self, output): + def _get_normalized_output_text(self, output): # Some tests produce "\r\n" explicitly. Our system (Python/Cygwin) # helpfully changes the "\n" to "\r\n", resulting in "\r\r\n". norm = output.replace("\r\r\n", "\r\n").strip("\r\n").replace( "\r\n", "\n") return norm + "\n" - def get_normalized_expected_text(self, filename, show_sources): + def _get_normalized_expected_text(self, filename): """Given the filename of the test, read the expected output from a file and normalize the text. Returns a string with the expected text, or '' if the expected output file was not found.""" # Read the port-specific expected text. expected_filename = self._port.expected_filename(filename, '.txt') - if show_sources: - _log.debug('Using %s' % expected_filename) + return self._get_normalized_text(expected_filename) - return self.get_normalized_text(expected_filename) - - def get_normalized_text(self, filename): + def _get_normalized_text(self, filename): # FIXME: We repeat this pattern often, we should share code. try: # NOTE: -expected.txt files are ALWAYS utf-8. However, @@ -94,13 +91,12 @@ class TestTextDiff(test_type_base.TestTypeBase): # 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, output, ".txt", encoding=None, - generate_new_baseline=test_args.new_baseline) + generate_new_baseline=test_args.new_baseline) return failures # Normalize text to diff - output = self.get_normalized_output_text(output) - expected = self.get_normalized_expected_text(filename, - test_args.show_sources) + output = self._get_normalized_output_text(output) + expected = self._get_normalized_expected_text(filename) # Write output files for new tests, too. if port.compare_text(output, expected): @@ -127,5 +123,5 @@ class TestTextDiff(test_type_base.TestTypeBase): False otherwise. """ - return port.compare_text(self.get_normalized_text(file1), - self.get_normalized_text(file2)) + return port.compare_text(self._get_normalized_text(file1), + self._get_normalized_text(file2)) diff --git a/WebKitTools/Scripts/webkitpy/style/checker.py b/WebKitTools/Scripts/webkitpy/style/checker.py index e3c56c5..ee33003 100644 --- a/WebKitTools/Scripts/webkitpy/style/checker.py +++ b/WebKitTools/Scripts/webkitpy/style/checker.py @@ -38,6 +38,7 @@ from checkers.common import categories as CommonCategories from checkers.common import CarriageReturnChecker from checkers.cpp import CppChecker from checkers.python import PythonChecker +from checkers.test_expectations import TestExpectationsChecker from checkers.text import TextChecker from error_handlers import DefaultStyleErrorHandler from filter import FilterConfiguration @@ -234,6 +235,7 @@ def _all_categories(): """Return the set of all categories used by check-webkit-style.""" # Take the union across all checkers. categories = CommonCategories.union(CppChecker.categories) + categories = categories.union(TestExpectationsChecker.categories) # FIXME: Consider adding all of the pep8 categories. Since they # are not too meaningful for documentation purposes, for @@ -399,10 +401,15 @@ class CheckerDispatcher(object): # Since "LayoutTests" is in _SKIPPED_FILES_WITHOUT_WARNING, make # an exception to prevent files like "LayoutTests/ChangeLog" and # "LayoutTests/ChangeLog-2009-06-16" from being skipped. + # Files like 'test_expectations.txt' and 'drt_expectations.txt' + # are also should not be skipped. # # FIXME: Figure out a good way to avoid having to add special logic # for this special case. - if os.path.basename(file_path).startswith('ChangeLog'): + basename = os.path.basename(file_path) + if basename.startswith('ChangeLog'): + return False + elif basename == 'test_expectations.txt' or basename == 'drt_expectations.txt': return False for skipped_file in _SKIPPED_FILES_WITHOUT_WARNING: if file_path.find(skipped_file) >= 0: @@ -442,7 +449,11 @@ class CheckerDispatcher(object): elif file_type == FileType.PYTHON: checker = PythonChecker(file_path, handle_style_error) elif file_type == FileType.TEXT: - checker = TextChecker(file_path, handle_style_error) + basename = os.path.basename(file_path) + if basename == 'test_expectations.txt' or basename == 'drt_expectations.txt': + checker = TestExpectationsChecker(file_path, handle_style_error) + else: + checker = TextChecker(file_path, handle_style_error) else: raise ValueError('Invalid file type "%(file_type)s": the only valid file types ' "are %(NONE)s, %(CPP)s, and %(TEXT)s." diff --git a/WebKitTools/Scripts/webkitpy/style/checkers/common.py b/WebKitTools/Scripts/webkitpy/style/checkers/common.py index a2d933f..76aa956 100644 --- a/WebKitTools/Scripts/webkitpy/style/checkers/common.py +++ b/WebKitTools/Scripts/webkitpy/style/checkers/common.py @@ -30,7 +30,7 @@ # into a shared location and refactoring appropriately. categories = set([ "whitespace/carriage_return", -]) + "whitespace/tab"]) class CarriageReturnChecker(object): @@ -55,3 +55,20 @@ class CarriageReturnChecker(object): lines[line_number] = lines[line_number].rstrip("\r") return lines + + +class TabChecker(object): + + """Supports checking for and handling tabs.""" + + def __init__(self, file_path, handle_style_error): + self.file_path = file_path + self.handle_style_error = handle_style_error + + def check(self, lines): + # FIXME: share with cpp_style. + for line_number, line in enumerate(lines): + if "\t" in line: + self.handle_style_error(line_number + 1, + "whitespace/tab", 5, + "Line contains tab character.") diff --git a/WebKitTools/Scripts/webkitpy/style/checkers/common_unittest.py b/WebKitTools/Scripts/webkitpy/style/checkers/common_unittest.py index b67b7b0..1fe1263 100644 --- a/WebKitTools/Scripts/webkitpy/style/checkers/common_unittest.py +++ b/WebKitTools/Scripts/webkitpy/style/checkers/common_unittest.py @@ -25,7 +25,7 @@ import unittest from common import CarriageReturnChecker - +from common import TabChecker # FIXME: The unit tests for the cpp, text, and common checkers should # share supporting test code. This can include, for example, the @@ -92,3 +92,33 @@ class CarriageReturnCheckerTest(unittest.TestCase): self.assert_carriage_return(["line1", "line2\r", "line3\r"], ["line1", "line2", "line3"], [2, 3]) + + +class TabCheckerTest(unittest.TestCase): + + """Tests for TabChecker.""" + + def assert_tab(self, input_lines, error_lines): + """Assert when the given lines contain tabs.""" + self._error_lines = [] + + def style_error_handler(line_number, category, confidence, message): + self.assertEqual(category, 'whitespace/tab') + self.assertEqual(confidence, 5) + self.assertEqual(message, 'Line contains tab character.') + self._error_lines.append(line_number) + + checker = TabChecker('', style_error_handler) + checker.check(input_lines) + self.assertEquals(self._error_lines, error_lines) + + def test_notab(self): + self.assert_tab([''], []) + self.assert_tab(['foo', 'bar'], []) + + def test_tab(self): + self.assert_tab(['\tfoo'], [1]) + self.assert_tab(['line1', '\tline2', 'line3\t'], [2, 3]) + +if __name__ == '__main__': + unittest.main() diff --git a/WebKitTools/Scripts/webkitpy/style/checkers/test_expectations.py b/WebKitTools/Scripts/webkitpy/style/checkers/test_expectations.py new file mode 100644 index 0000000..ddc3983 --- /dev/null +++ b/WebKitTools/Scripts/webkitpy/style/checkers/test_expectations.py @@ -0,0 +1,124 @@ +# 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. + +"""Checks WebKit style for test_expectations files.""" + +import logging +import os +import re +import sys + +from common import TabChecker +from webkitpy.style_references import port +from webkitpy.style_references import test_expectations + +_log = logging.getLogger("webkitpy.style.checkers.test_expectations") + + +class ChromiumOptions(object): + """A mock object for creating chromium port object. + + port.get() requires an options object which has 'chromium' attribute to create + chromium port object for each platform. This class mocks such object. + """ + def __init__(self): + self.chromium = True + self.use_drt = True + + +class TestExpectationsChecker(object): + """Processes test_expectations.txt lines for validating the syntax.""" + + categories = set(['test/expectations']) + + def __init__(self, file_path, handle_style_error): + self._file_path = file_path + self._handle_style_error = handle_style_error + self._tab_checker = TabChecker(file_path, handle_style_error) + self._output_regex = re.compile('Line:(?P<line>\d+)\s*(?P<message>.+)') + # Determining the port of this expectations. + try: + port_name = self._file_path.split(os.sep)[-2] + if port_name == "chromium": + options = ChromiumOptions() + self._port_obj = port.get(port_name=None, options=options) + else: + self._port_obj = port.get(port_name=port_name) + except: + # Using 'test' port when we couldn't determine the port for this + # expectations. + _log.warn("Could not determine the port for %s. " + "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." + "test_expectations") + log.setLevel(logging.CRITICAL) + + def _handle_error_message(self, lineno, message, confidence): + pass + + def check_test_expectations(self, expectations_str, tests=None, overrides=None): + errors = [] + expectations = None + 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, + is_lint_mode=True, suppress_errors=False, tests_are_present=True, + overrides=overrides) + except SyntaxError, error: + errors = str(error).splitlines() + + for error in errors: + matched = self._output_regex.match(error) + if matched: + lineno, message = matched.group('line', 'message') + self._handle_style_error(int(lineno), 'test/expectations', 5, message) + + if expectations: + for error in expectations.get_non_fatal_errors(): + matched = self._output_regex.match(error) + if matched: + lineno, message = matched.group('line', 'message') + self._handle_style_error(int(lineno), 'test/expectations', 2, message) + + def check_tabs(self, lines): + self._tab_checker.check(lines) + + def check(self, lines): + overrides = self._port_obj.test_expectations_overrides() + expectations = '\n'.join(lines) + self.check_test_expectations(expectations_str=expectations, + tests=None, + overrides=overrides) + # Warn tabs in lines as well + self.check_tabs(lines) diff --git a/WebKitTools/Scripts/webkitpy/style/checkers/test_expectations_unittest.py b/WebKitTools/Scripts/webkitpy/style/checkers/test_expectations_unittest.py new file mode 100644 index 0000000..aa219b2 --- /dev/null +++ b/WebKitTools/Scripts/webkitpy/style/checkers/test_expectations_unittest.py @@ -0,0 +1,172 @@ +#!/usr/bin/python +# Copyright (C) 2010 Google Inc. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following disclaimer +# in the documentation and/or other materials provided with the +# distribution. +# * Neither the name of Google Inc. nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +"""Unit tests for test_expectations.py.""" + +import os +import sys +import unittest + +# We need following workaround hack to run this unit tests in stand-alone. +try: + d = os.path.dirname(__file__) +except NameError: + d = os.path.dirname(sys.argv[0]) +sys.path.append(os.path.abspath(os.path.join(d, '../../../'))) + +from test_expectations import TestExpectationsChecker +from webkitpy.style_references import port +from webkitpy.style_references import test_expectations as test_expectations_style + + +class ErrorCollector(object): + """An error handler class for unit tests.""" + + def __init__(self): + self._errors = [] + + def __call__(self, lineno, category, confidence, message): + self._errors.append('%s [%s] [%d]' % (message, category, confidence)) + + def get_errors(self): + return ''.join(self._errors) + + def reset_errors(self): + self._errors = [] + + +class TestExpectationsTestCase(unittest.TestCase): + """TestCase for test_expectations.py""" + + def setUp(self): + self._error_collector = ErrorCollector() + port_obj = port.get('test') + self._test_file = os.path.join(port_obj.layout_tests_dir(), 'misc/passing.html') + + def process_expectations(self, expectations, overrides=None): + self._checker = TestExpectationsChecker() + + def assert_lines_lint(self, lines, expected): + self._error_collector.reset_errors() + checker = TestExpectationsChecker('test/test_expectations.txt', + self._error_collector) + checker.check_test_expectations(expectations_str='\n'.join(lines), + tests=[self._test_file], + overrides=None) + checker.check_tabs(lines) + self.assertEqual(expected, self._error_collector.get_errors()) + + def test_valid_expectations(self): + self.assert_lines_lint( + ["misc/passing.html = PASS"], + "") + self.assert_lines_lint( + ["misc/passing.html = FAIL PASS"], + "") + self.assert_lines_lint( + ["misc/passing.html = CRASH TIMEOUT FAIL PASS"], + "") + self.assert_lines_lint( + ["BUG1234 TEST : misc/passing.html = PASS FAIL"], + "") + self.assert_lines_lint( + ["SKIP BUG1234 : misc/passing.html = TIMEOUT PASS"], + "") + self.assert_lines_lint( + ["BUG1234 DEBUG : misc/passing.html = TIMEOUT PASS"], + "") + self.assert_lines_lint( + ["BUG1234 DEBUG SKIP : misc/passing.html = TIMEOUT PASS"], + "") + self.assert_lines_lint( + ["BUG1234 TEST DEBUG SKIP : misc/passing.html = TIMEOUT PASS"], + "") + self.assert_lines_lint( + ["BUG1234 DEBUG TEST : misc/passing.html = TIMEOUT PASS"], + "") + self.assert_lines_lint( + ["SLOW DEFER BUG1234 : misc/passing.html = PASS"], + "") + self.assert_lines_lint( + ["WONTFIX SKIP : misc/passing.html = TIMEOUT"], + "") + + def test_valid_modifiers(self): + self.assert_lines_lint( + ["INVALID-MODIFIER : misc/passing.html = PASS"], + "Invalid modifier for test: invalid-modifier " + "misc/passing.html [test/expectations] [5]") + self.assert_lines_lint( + ["SKIP : misc/passing.html = PASS"], + "Test lacks BUG modifier. " + "misc/passing.html [test/expectations] [2]") + self.assert_lines_lint( + ["WONTFIX DEFER : misc/passing.html = PASS"], + "Test cannot be both DEFER and WONTFIX. " + "misc/passing.html [test/expectations] [5]") + + def test_expectation_errors(self): + self.assert_lines_lint( + ["missing expectations"], + "Missing expectations. ['missing expectations'] [test/expectations] [5]") + self.assert_lines_lint( + ["SLOW : misc/passing.html = TIMEOUT"], + "A test can not be both slow and timeout. " + "If it times out indefinitely, then it should be just timeout. " + "misc/passing.html [test/expectations] [5]") + self.assert_lines_lint( + ["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( + ["misc/passing.html = PASS"], + "") + self.assert_lines_lint( + ["misc/passing.html = UNSUPPORTED"], + "Unsupported expectation: unsupported " + "misc/passing.html [test/expectations] [5]") + self.assert_lines_lint( + ["misc/passing.html = PASS UNSUPPORTED"], + "Unsupported expectation: unsupported " + "misc/passing.html [test/expectations] [5]") + + def test_already_seen_test(self): + self.assert_lines_lint( + ["misc/passing.html = PASS", + "misc/passing.html = TIMEOUT"], + "Duplicate expectation. %s [test/expectations] [5]" % self._test_file) + + def test_tab(self): + self.assert_lines_lint( + ["\tmisc/passing.html = PASS"], + "Line contains tab character. [whitespace/tab] [5]") + +if __name__ == '__main__': + unittest.main() diff --git a/WebKitTools/Scripts/webkitpy/style/checkers/text.py b/WebKitTools/Scripts/webkitpy/style/checkers/text.py index 0d03938..1147658 100644 --- a/WebKitTools/Scripts/webkitpy/style/checkers/text.py +++ b/WebKitTools/Scripts/webkitpy/style/checkers/text.py @@ -29,6 +29,7 @@ """Checks WebKit style for text files.""" +from common import TabChecker class TextChecker(object): @@ -37,16 +38,10 @@ class TextChecker(object): def __init__(self, file_path, handle_style_error): self.file_path = file_path self.handle_style_error = handle_style_error + self._tab_checker = TabChecker(file_path, handle_style_error) def check(self, lines): - lines = (["// adjust line numbers to make the first line 1."] + lines) - - # FIXME: share with cpp_style. - for line_number, line in enumerate(lines): - if "\t" in line: - self.handle_style_error(line_number, - "whitespace/tab", 5, - "Line contains tab character.") + self._tab_checker.check(lines) # FIXME: Remove this function (requires refactoring unit tests). diff --git a/WebKitTools/Scripts/webkitpy/style_references.py b/WebKitTools/Scripts/webkitpy/style_references.py index a42b69d..34f3bff 100644 --- a/WebKitTools/Scripts/webkitpy/style_references.py +++ b/WebKitTools/Scripts/webkitpy/style_references.py @@ -45,6 +45,8 @@ from webkitpy.common.system.logtesting import LogTesting from webkitpy.common.system.logtesting import TestLogStream from webkitpy.common.system.logutils import configure_logging from webkitpy.common.checkout.scm import detect_scm_system +from webkitpy.layout_tests import port +from webkitpy.layout_tests.layout_package import test_expectations from webkitpy.thirdparty.autoinstalled import pep8 diff --git a/WebKitTools/Scripts/webkitpy/thirdparty/simplejson/decoder.py b/WebKitTools/Scripts/webkitpy/thirdparty/simplejson/decoder.py index b887b58..63f70cb 100644 --- a/WebKitTools/Scripts/webkitpy/thirdparty/simplejson/decoder.py +++ b/WebKitTools/Scripts/webkitpy/thirdparty/simplejson/decoder.py @@ -3,7 +3,7 @@ Implementation of JSONDecoder """ import re -from .scanner import Scanner, pattern +from scanner import Scanner, pattern FLAGS = re.VERBOSE | re.MULTILINE | re.DOTALL diff --git a/WebKitTools/Scripts/webkitpy/tool/main.py b/WebKitTools/Scripts/webkitpy/tool/main.py index 1f43145..0dd5017 100755 --- a/WebKitTools/Scripts/webkitpy/tool/main.py +++ b/WebKitTools/Scripts/webkitpy/tool/main.py @@ -33,7 +33,7 @@ import os import threading from webkitpy.common.checkout.api import Checkout -from webkitpy.common.checkout.scm import detect_scm_system +from webkitpy.common.checkout.scm import default_scm from webkitpy.common.net.bugzilla import Bugzilla from webkitpy.common.net.buildbot import BuildBot from webkitpy.common.net.rietveld import Rietveld @@ -79,18 +79,8 @@ class WebKitPatch(MultiCommandTool): def scm(self): # Lazily initialize SCM to not error-out before command line parsing (or when running non-scm commands). - original_cwd = os.path.abspath(".") if not self._scm: - self._scm = detect_scm_system(original_cwd) - - if not self._scm: - script_directory = os.path.abspath(sys.path[0]) - self._scm = detect_scm_system(script_directory) - if self._scm: - log("The current directory (%s) is not a WebKit checkout, using %s" % (original_cwd, self._scm.checkout_root)) - else: - error("FATAL: Failed to determine the SCM system for either %s or %s" % (original_cwd, script_directory)) - + self._scm = default_scm() return self._scm def checkout(self): diff --git a/WebKitTools/Scripts/webkitpy/tool/steps/runtests.py b/WebKitTools/Scripts/webkitpy/tool/steps/runtests.py index 22b9452..0f57439 100644 --- a/WebKitTools/Scripts/webkitpy/tool/steps/runtests.py +++ b/WebKitTools/Scripts/webkitpy/tool/steps/runtests.py @@ -57,6 +57,7 @@ class RunTests(AbstractStep): if self._options.non_interactive: args.append("--no-launch-safari") args.append("--exit-after-n-failures=1") + args.append("--wait-for-httpd") # FIXME: Hack to work around https://bugs.webkit.org/show_bug.cgi?id=38912 # when running the commit-queue on a mac leopard machine since compositing # does not work reliably on Leopard due to various graphics driver/system bugs. diff --git a/WebKitTools/Scripts/webkitpy/tool/steps/steps_unittest.py b/WebKitTools/Scripts/webkitpy/tool/steps/steps_unittest.py index 766801b..f4c955d 100644 --- a/WebKitTools/Scripts/webkitpy/tool/steps/steps_unittest.py +++ b/WebKitTools/Scripts/webkitpy/tool/steps/steps_unittest.py @@ -77,6 +77,6 @@ MOCK run_and_throw_if_fail: ['WebKitTools/Scripts/test-webkitperl'] Running JavaScriptCore tests MOCK run_and_throw_if_fail: ['WebKitTools/Scripts/run-javascriptcore-tests'] Running run-webkit-tests -MOCK run_and_throw_if_fail: ['WebKitTools/Scripts/run-webkit-tests', '--no-launch-safari', '--exit-after-n-failures=1', '--ignore-tests', 'compositing', '--quiet'] +MOCK run_and_throw_if_fail: ['WebKitTools/Scripts/run-webkit-tests', '--no-launch-safari', '--exit-after-n-failures=1', '--wait-for-httpd', '--ignore-tests', 'compositing', '--quiet'] """ OutputCapture().assert_outputs(self, step.run, [{}], expected_stderr=expected_stderr) diff --git a/WebKitTools/TestResultServer/handlers/testfilehandler.py b/WebKitTools/TestResultServer/handlers/testfilehandler.py index 97953e7..4d1320f 100644 --- a/WebKitTools/TestResultServer/handlers/testfilehandler.py +++ b/WebKitTools/TestResultServer/handlers/testfilehandler.py @@ -43,6 +43,7 @@ PARAM_NAME = "name" PARAM_KEY = "key" PARAM_TEST_TYPE = "testtype" PARAM_INCREMENTAL = "incremental" +PARAM_TEST_LIST_JSON = "testlistjson" class DeleteFile(webapp.RequestHandler): @@ -109,16 +110,31 @@ class GetFile(webapp.RequestHandler): if not files: logging.info("File not found, builder: %s, test_type: %s, name: %s.", builder, test_type, name) - return + return None + + return files[0].data + + def _get_test_list_json(self, builder, test_type): + """Return json file with test name list only, do not include test + results and other non-test-data . - self.response.headers["Content-Type"] = "text/plain; charset=utf-8" - self.response.out.write(files[0].data) + Args: + builder: builder name. + test_type: type of test results. + """ + + json = self._get_file_content(builder, test_type, "results.json") + if not json: + return None + + return JsonResults.get_test_list(builder, json) def get(self): builder = self.request.get(PARAM_BUILDER) test_type = self.request.get(PARAM_TEST_TYPE) name = self.request.get(PARAM_NAME) dir = self.request.get(PARAM_DIR) + test_list_json = self.request.get(PARAM_TEST_LIST_JSON) logging.debug( "Getting files, builder: %s, test_type: %s, name: %s.", @@ -129,8 +145,15 @@ class GetFile(webapp.RequestHandler): # file content. if dir or not builder or not name: return self._get_file_list(builder, test_type, name) + + if name == "results.json" and test_list_json: + json = self._get_test_list_json(builder, test_type) else: - return self._get_file_content(builder, test_type, name) + json = self._get_file_content(builder, test_type, name) + + if json: + self.response.headers["Content-Type"] = "text/plain; charset=utf-8" + self.response.out.write(json) class Upload(webapp.RequestHandler): diff --git a/WebKitTools/TestResultServer/model/jsonresults.py b/WebKitTools/TestResultServer/model/jsonresults.py index d86fbcd..e5eb7f7 100755 --- a/WebKitTools/TestResultServer/model/jsonresults.py +++ b/WebKitTools/TestResultServer/model/jsonresults.py @@ -40,8 +40,11 @@ JSON_RESULTS_BUILD_NUMBERS = "buildNumbers" JSON_RESULTS_TESTS = "tests" JSON_RESULTS_RESULTS = "results" JSON_RESULTS_TIMES = "times" +JSON_RESULTS_PASS = "P" +JSON_RESULTS_NO_DATA = "N" +JSON_RESULTS_MIN_TIME = 1 JSON_RESULTS_VERSION = 3 -JSON_RESULTS_MAX_BUILDS = 750 +JSON_RESULTS_MAX_BUILDS = 1500 class JsonResults(object): @@ -171,8 +174,6 @@ class JsonResults(object): # Merge this build into aggreagated results. cls._merge_one_build(aggregated_json, incremental_json, index) - logging.debug("Merged build %s, merged json: %s.", - build_number, aggregated_json) return True @@ -210,18 +211,26 @@ class JsonResults(object): incremental_json: incremental json object. """ - for test_name in incremental_json: - incremental_test = incremental_json[test_name] + all_tests = (set(aggregated_json.iterkeys()) | + set(incremental_json.iterkeys())) + for test_name in all_tests: if test_name in aggregated_json: aggregated_test = aggregated_json[test_name] + if test_name in incremental_json: + incremental_test = incremental_json[test_name] + results = incremental_test[JSON_RESULTS_RESULTS] + times = incremental_test[JSON_RESULTS_TIMES] + else: + results = [[1, JSON_RESULTS_NO_DATA]] + times = [[1, 0]] + cls._insert_item_run_length_encoded( - incremental_test[JSON_RESULTS_RESULTS], - aggregated_test[JSON_RESULTS_RESULTS]) + results, aggregated_test[JSON_RESULTS_RESULTS]) cls._insert_item_run_length_encoded( - incremental_test[JSON_RESULTS_TIMES], - aggregated_test[JSON_RESULTS_TIMES]) + times, aggregated_test[JSON_RESULTS_TIMES]) + cls._normalize_results_json(test_name, aggregated_json) else: - aggregated_json[test_name] = incremental_test + aggregated_json[test_name] = incremental_json[test_name] @classmethod def _insert_item_run_length_encoded(cls, incremental_item, aggregated_item): @@ -238,17 +247,69 @@ class JsonResults(object): aggregated_item[0][0] = min( aggregated_item[0][0] + item[0], JSON_RESULTS_MAX_BUILDS) else: - # The test item values need to be summed from continuous runs. - # If there is an older item (not most recent one) whose value is - # same as the one to insert, then we should remove the old item - # from aggregated list. - for i in reversed(range(1, len(aggregated_item))): - if item[1] == aggregated_item[i][1]: - aggregated_item.pop(i) - aggregated_item.insert(0, item) @classmethod + def _normalize_results_json(cls, test_name, aggregated_json): + """ Prune tests where all runs pass or tests that no longer exist and + truncate all results to JSON_RESULTS_MAX_BUILDS. + + Args: + test_name: Name of the test. + aggregated_json: The JSON object with all the test results for + this builder. + """ + + aggregated_test = aggregated_json[test_name] + aggregated_test[JSON_RESULTS_RESULTS] = \ + cls._remove_items_over_max_number_of_builds( + aggregated_test[JSON_RESULTS_RESULTS]) + aggregated_test[JSON_RESULTS_TIMES] = \ + cls._remove_items_over_max_number_of_builds( + aggregated_test[JSON_RESULTS_TIMES]) + + is_all_pass = cls._is_results_all_of_type( + aggregated_test[JSON_RESULTS_RESULTS], JSON_RESULTS_PASS) + is_all_no_data = cls._is_results_all_of_type( + aggregated_test[JSON_RESULTS_RESULTS], JSON_RESULTS_NO_DATA) + + max_time = max( + [time[1] for time in aggregated_test[JSON_RESULTS_TIMES]]) + # Remove all passes/no-data from the results to reduce noise and + # filesize. If a test passes every run, but + # takes >= JSON_RESULTS_MIN_TIME to run, don't throw away the data. + if (is_all_no_data or + (is_all_pass and max_time < JSON_RESULTS_MIN_TIME)): + del aggregated_json[test_name] + + @classmethod + def _remove_items_over_max_number_of_builds(cls, encoded_list): + """Removes items from the run-length encoded list after the final + item that exceeds the max number of builds to track. + + Args: + encoded_results: run-length encoded results. An array of arrays, e.g. + [[3,'A'],[1,'Q']] encodes AAAQ. + """ + num_builds = 0 + index = 0 + for result in encoded_list: + num_builds = num_builds + result[0] + index = index + 1 + if num_builds > JSON_RESULTS_MAX_BUILDS: + return encoded_list[:index] + + return encoded_list + + @classmethod + def _is_results_all_of_type(cls, results, type): + """Returns whether all the results are of the given type + (e.g. all passes). + """ + + return len(results) == 1 and results[0][1] == type + + @classmethod def _check_json(cls, builder, json): """Check whether the given json is valid. @@ -363,3 +424,33 @@ class JsonResults(object): return None return file + + @classmethod + def get_test_list(cls, builder, json_file_data): + """Get list of test names from aggregated json file data. + + Args: + json_file_data: json file data that has all test-data and + non-test-data. + + Returns: + json file with test name list only. The json format is the same + as the one saved in datastore, but all non-test-data and test detail + results are removed. + """ + + logging.debug("Loading test results json...") + json = cls._load_json(json_file_data) + if not json: + return None + + logging.debug("Checking test results json...") + if not cls._check_json(builder, json): + return None + + test_list_json = {} + tests = json[builder][JSON_RESULTS_TESTS] + test_list_json[builder] = { + "tests": dict.fromkeys(tests, {})} + + return cls._generate_file_data(test_list_json) diff --git a/WebKitTools/TestResultServer/model/jsonresults_unittest.py b/WebKitTools/TestResultServer/model/jsonresults_unittest.py index fd646c8..15b659b 100755 --- a/WebKitTools/TestResultServer/model/jsonresults_unittest.py +++ b/WebKitTools/TestResultServer/model/jsonresults_unittest.py @@ -26,6 +26,7 @@ # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +import jsonresults import unittest from jsonresults import JsonResults @@ -65,6 +66,9 @@ JSON_RESULTS_TESTS_TEMPLATE = ( JSON_RESULTS_PREFIX = "ADD_RESULTS(" JSON_RESULTS_SUFFIX = ");" +JSON_RESULTS_TEST_LIST_TEMPLATE = ( + '{"Webkit":{"tests":{[TESTDATA_TESTS]}}}') + class JsonResultsTest(unittest.TestCase): def setUp(self): @@ -122,12 +126,27 @@ class JsonResultsTest(unittest.TestCase): else: self.assertFalse(merged_results) + def _test_get_test_list(self, input_data, expected_data): + input_results = self._make_test_json(input_data) + + json_tests = [] + for test in expected_data: + json_tests.append("\"" + test + "\":{}") + + expected_results = JSON_RESULTS_PREFIX + \ + JSON_RESULTS_TEST_LIST_TEMPLATE.replace( + "[TESTDATA_TESTS]", ",".join(json_tests)) + \ + JSON_RESULTS_SUFFIX + + actual_results = JsonResults.get_test_list(self._builder, input_results) + self.assertEquals(actual_results, expected_results) + def test(self): # Empty incremental results json. # Nothing to merge. self._test_merge( # Aggregated results - (["2", "1"], [["001.html", "[200,\"P\"]", "[200,\"0\"]"]]), + (["2", "1"], [["001.html", "[200,\"F\"]", "[200,0]"]]), # Incremental results None, # Expect no merge happens. @@ -137,7 +156,7 @@ class JsonResultsTest(unittest.TestCase): # Nothing to merge. self._test_merge( # Aggregated results - (["2", "1"], [["001.html", "[200,\"P\"]", "[200,\"0\"]"]]), + (["2", "1"], [["001.html", "[200,\"F\"]", "[200,0]"]]), # Incremental results ([], []), # Expected no merge happens. @@ -149,9 +168,9 @@ class JsonResultsTest(unittest.TestCase): # Aggregated results None, # Incremental results - (["2", "1"], [["001.html", "[200,\"P\"]", "[200,\"0\"]"]]), + (["2", "1"], [["001.html", "[200,\"F\"]", "[200,0]"]]), # Expected results - (["2", "1"], [["001.html", "[200,\"P\"]", "[200,\"0\"]"]])) + (["2", "1"], [["001.html", "[200,\"F\"]", "[200,0]"]])) # Single test for single run. # Incremental results has the latest build and same test results for @@ -160,11 +179,11 @@ class JsonResultsTest(unittest.TestCase): # of runs for "P" (200 + 1) to get merged results. self._test_merge( # Aggregated results - (["2", "1"], [["001.html", "[200,\"P\"]", "[200,\"0\"]"]]), + (["2", "1"], [["001.html", "[200,\"F\"]", "[200,0]"]]), # Incremental results - (["3"], [["001.html", "[1,\"P\"]", "[1,\"0\"]"]]), + (["3"], [["001.html", "[1,\"F\"]", "[1,0]"]]), # Expected results - (["3", "2", "1"], [["001.html", "[201,\"P\"]", "[201,\"0\"]"]])) + (["3", "2", "1"], [["001.html", "[201,\"F\"]", "[201,0]"]])) # Single test for single run. # Incremental results has the latest build but different test results @@ -172,72 +191,68 @@ class JsonResultsTest(unittest.TestCase): # Insert the incremental results at the first place. self._test_merge( # Aggregated results - (["2", "1"], [["001.html", "[200,\"P\"]", "[200,\"0\"]"]]), + (["2", "1"], [["001.html", "[200,\"F\"]", "[200,0]"]]), # Incremental results - (["3"], [["001.html", "[1, \"I\"]", "[1,\"1\"]"]]), + (["3"], [["001.html", "[1, \"I\"]", "[1,1]"]]), # Expected results - (["3", "2", "1"], [["001.html", "[1,\"I\"],[200,\"P\"]", "[1,\"1\"],[200,\"0\"]"]])) + (["3", "2", "1"], [["001.html", "[1,\"I\"],[200,\"F\"]", "[1,1],[200,0]"]])) # Single test for single run. # Incremental results has the latest build but different test results # for that run. - # The test "results" and "times" need to be continuous, so the old - # [10,"I"] result should be dropped because a new result of same type [1,"I"] - # is inserted in front of [200,"P"]. self._test_merge( # Aggregated results - (["2", "1"], [["001.html", "[200,\"P\"],[10,\"I\"]", "[200,\"0\"],[10,\"1\"]"]]), + (["2", "1"], [["001.html", "[200,\"F\"],[10,\"I\"]", "[200,0],[10,1]"]]), # Incremental results - (["3"], [["001.html", "[1,\"I\"]", "[1,\"1\"]"]]), + (["3"], [["001.html", "[1,\"I\"]", "[1,1]"]]), # Expected results - (["3", "2", "1"], [["001.html", "[1,\"I\"],[200,\"P\"]", "[1,\"1\"],[200,\"0\"]"]])) + (["3", "2", "1"], [["001.html", "[1,\"I\"],[200,\"F\"],[10,\"I\"]", "[1,1],[200,0],[10,1]"]])) # Multiple tests for single run. # All tests have incremental updates. self._test_merge( # Aggregated results - (["2", "1"], [["001.html", "[200,\"P\"]", "[200,\"0\"]"], ["002.html", "[100,\"I\"]", "[100,\"1\"]"]]), + (["2", "1"], [["001.html", "[200,\"F\"]", "[200,0]"], ["002.html", "[100,\"I\"]", "[100,1]"]]), # Incremental results - (["3"], [["001.html", "[1,\"P\"]", "[1,\"0\"]"], ["002.html", "[1,\"I\"]", "[1,\"1\"]"]]), + (["3"], [["001.html", "[1,\"F\"]", "[1,0]"], ["002.html", "[1,\"I\"]", "[1,1]"]]), # Expected results - (["3", "2", "1"], [["001.html", "[201,\"P\"]", "[201,\"0\"]"], ["002.html", "[101,\"I\"]", "[101,\"1\"]"]])) + (["3", "2", "1"], [["001.html", "[201,\"F\"]", "[201,0]"], ["002.html", "[101,\"I\"]", "[101,1]"]])) # Multiple tests for single run. - # Not all tests have update. self._test_merge( # Aggregated results - (["2", "1"], [["001.html", "[200,\"P\"]", "[200,\"0\"]"], ["002.html", "[100,\"I\"]", "[100,\"1\"]"]]), + (["2", "1"], [["001.html", "[200,\"F\"]", "[200,0]"], ["002.html", "[100,\"I\"]", "[100,1]"]]), # Incremental results - (["3"], [["002.html", "[1,\"I\"]", "[1,\"1\"]"]]), + (["3"], [["002.html", "[1,\"I\"]", "[1,1]"]]), # Expected results - (["3", "2", "1"], [["001.html", "[200,\"P\"]", "[200,\"0\"]"], ["002.html", "[101,\"I\"]", "[101,\"1\"]"]])) + (["3", "2", "1"], [["001.html", "[1,\"N\"],[200,\"F\"]", "[201,0]"], ["002.html", "[101,\"I\"]", "[101,1]"]])) # Single test for multiple runs. self._test_merge( # Aggregated results - (["2", "1"], [["001.html", "[200,\"P\"]", "[200,\"0\"]"]]), + (["2", "1"], [["001.html", "[200,\"F\"]", "[200,0]"]]), # Incremental results - (["4", "3"], [["001.html", "[2, \"I\"]", "[2,\"2\"]"]]), + (["4", "3"], [["001.html", "[2, \"I\"]", "[2,2]"]]), # Expected results - (["4", "3", "2", "1"], [["001.html", "[2,\"I\"],[200,\"P\"]", "[2,\"2\"],[200,\"0\"]"]])) + (["4", "3", "2", "1"], [["001.html", "[2,\"I\"],[200,\"F\"]", "[2,2],[200,0]"]])) # Multiple tests for multiple runs. self._test_merge( # Aggregated results - (["2", "1"], [["001.html", "[200,\"P\"]", "[200,\"0\"]"], ["002.html", "[10,\"Z\"]", "[10,\"0\"]"]]), + (["2", "1"], [["001.html", "[200,\"F\"]", "[200,0]"], ["002.html", "[10,\"Z\"]", "[10,0]"]]), # Incremental results - (["4", "3"], [["001.html", "[2, \"I\"]", "[2,\"2\"]"], ["002.html", "[1,\"C\"]", "[1,\"1\"]"]]), + (["4", "3"], [["001.html", "[2, \"I\"]", "[2,2]"], ["002.html", "[1,\"C\"]", "[1,1]"]]), # Expected results - (["4", "3", "2", "1"], [["001.html", "[2,\"I\"],[200,\"P\"]", "[2,\"2\"],[200,\"0\"]"], ["002.html", "[1,\"C\"],[10,\"Z\"]", "[1,\"1\"],[10,\"0\"]"]])) + (["4", "3", "2", "1"], [["001.html", "[2,\"I\"],[200,\"F\"]", "[2,2],[200,0]"], ["002.html", "[1,\"C\"],[10,\"Z\"]", "[1,1],[10,0]"]])) # Test the build in incremental results is older than the most recent # build in aggregated results. # The incremental results should be dropped and no merge happens. self._test_merge( # Aggregated results - (["3", "1"], [["001.html", "[200,\"P\"]", "[200,\"0\"]"]]), + (["3", "1"], [["001.html", "[200,\"F\"]", "[200,0]"]]), # Incremental results - (["2"], [["001.html", "[1, \"P\"]", "[1,\"0\"]"]]), + (["2"], [["001.html", "[1, \"F\"]", "[1,0]"]]), # Expected no merge happens. None) @@ -246,11 +261,57 @@ class JsonResultsTest(unittest.TestCase): # The incremental results should be dropped and no merge happens. self._test_merge( # Aggregated results - (["2", "1"], [["001.html", "[200,\"P\"]", "[200,\"0\"]"]]), + (["2", "1"], [["001.html", "[200,\"F\"]", "[200,0]"]]), # Incremental results - (["3", "2"], [["001.html", "[2, \"P\"]", "[2,\"0\"]"]]), + (["3", "2"], [["001.html", "[2, \"F\"]", "[2,0]"]]), # Expected no merge happens. None) + # Remove test where there is no data in all runs. + self._test_merge( + # Aggregated results + (["2", "1"], [["001.html", "[200,\"N\"]", "[200,0]"], ["002.html", "[10,\"F\"]", "[10,0]"]]), + # Incremental results + (["3"], [["001.html", "[1,\"N\"]", "[1,0]"], ["002.html", "[1,\"P\"]", "[1,0]"]]), + # Expected results + (["3", "2", "1"], [["002.html", "[1,\"P\"],[10,\"F\"]", "[11,0]"]])) + + # Remove test where all run pass and max running time < 1 seconds + self._test_merge( + # Aggregated results + (["2", "1"], [["001.html", "[200,\"P\"]", "[200,0]"], ["002.html", "[10,\"F\"]", "[10,0]"]]), + # Incremental results + (["3"], [["001.html", "[1,\"P\"]", "[1,0]"], ["002.html", "[1,\"P\"]", "[1,0]"]]), + # Expected results + (["3", "2", "1"], [["002.html", "[1,\"P\"],[10,\"F\"]", "[11,0]"]])) + + # Do not remove test where all run pass but max running time >= 1 seconds + self._test_merge( + # Aggregated results + (["2", "1"], [["001.html", "[200,\"P\"]", "[200,0]"], ["002.html", "[10,\"F\"]", "[10,0]"]]), + # Incremental results + (["3"], [["001.html", "[1,\"P\"]", "[1,1]"], ["002.html", "[1,\"P\"]", "[1,0]"]]), + # Expected results + (["3", "2", "1"], [["001.html", "[201,\"P\"]", "[1,1],[200,0]"], ["002.html", "[1,\"P\"],[10,\"F\"]", "[11,0]"]])) + + # Remove items from test results and times that exceeds the max number + # of builds to track. + max_builds = str(jsonresults.JSON_RESULTS_MAX_BUILDS) + self._test_merge( + # Aggregated results + (["2", "1"], [["001.html", "[" + max_builds + ",\"F\"],[1,\"I\"]", "[" + max_builds + ",0],[1,1]"]]), + # Incremental results + (["3"], [["001.html", "[1,\"T\"]", "[1,1]"]]), + # Expected results + (["3", "2", "1"], [["001.html", "[1,\"T\"],[" + max_builds + ",\"F\"]", "[1,1],[" + max_builds + ",0]"]])) + + # Get test name list only. Don't include non-test-list data and + # of test result details. + self._test_get_test_list( + # Input results + (["3", "2", "1"], [["001.html", "[200,\"P\"]", "[200,0]"], ["002.html", "[10,\"F\"]", "[10,0]"]]), + # Expected results + ["001.html", "002.html"]) + if __name__ == '__main__': unittest.main() diff --git a/WebKitTools/WebKitTestRunner/InjectedBundle/InjectedBundle.cpp b/WebKitTools/WebKitTestRunner/InjectedBundle/InjectedBundle.cpp index 02dfeb1..b2aa836 100644 --- a/WebKitTools/WebKitTestRunner/InjectedBundle/InjectedBundle.cpp +++ b/WebKitTools/WebKitTestRunner/InjectedBundle/InjectedBundle.cpp @@ -49,6 +49,7 @@ InjectedBundle& InjectedBundle::shared() InjectedBundle::InjectedBundle() : m_bundle(0) , m_mainPage(0) + , m_state(Idle) { } @@ -84,17 +85,6 @@ void InjectedBundle::initialize(WKBundleRef bundle) WKBundleActivateMacFontAscentHack(m_bundle); } -void InjectedBundle::done() -{ - WKRetainPtr<WKStringRef> doneMessageName(AdoptWK, WKStringCreateWithCFString(CFSTR("Done"))); - - std::string output = m_outputStream.str(); - RetainPtr<CFStringRef> outputCFString(AdoptCF, CFStringCreateWithCString(0, output.c_str(), kCFStringEncodingUTF8)); - WKRetainPtr<WKStringRef> doneMessageBody(AdoptWK, WKStringCreateWithCFString(outputCFString.get())); - - WKBundlePostMessage(m_bundle, doneMessageName.get(), doneMessageBody.get()); -} - void InjectedBundle::didCreatePage(WKBundlePageRef page) { // FIXME: we really need the main page ref to be sent over from the ui process @@ -121,7 +111,7 @@ void InjectedBundle::didReceiveMessage(WKStringRef messageName, WKTypeRef messag WKRetainPtr<WKStringRef> ackMessageBody(AdoptWK, WKStringCreateWithCFString(CFSTR("BeginTest"))); WKBundlePostMessage(m_bundle, ackMessageName.get(), ackMessageBody.get()); - reset(); + beginTesting(); return; } @@ -130,8 +120,10 @@ void InjectedBundle::didReceiveMessage(WKStringRef messageName, WKTypeRef messag WKBundlePostMessage(m_bundle, errorMessageName.get(), errorMessageBody.get()); } -void InjectedBundle::reset() +void InjectedBundle::beginTesting() { + m_state = Testing; + m_outputStream.str(""); m_layoutTestController = LayoutTestController::create(); @@ -144,6 +136,21 @@ void InjectedBundle::reset() m_mainPage->reset(); } +void InjectedBundle::done() +{ + m_mainPage->stopLoading(); + + WKRetainPtr<WKStringRef> doneMessageName(AdoptWK, WKStringCreateWithCFString(CFSTR("Done"))); + + std::string output = m_outputStream.str(); + RetainPtr<CFStringRef> outputCFString(AdoptCF, CFStringCreateWithCString(0, output.c_str(), kCFStringEncodingUTF8)); + WKRetainPtr<WKStringRef> doneMessageBody(AdoptWK, WKStringCreateWithCFString(outputCFString.get())); + + WKBundlePostMessage(m_bundle, doneMessageName.get(), doneMessageBody.get()); + + m_state = Idle; +} + void InjectedBundle::closeOtherPages() { Vector<WKBundlePageRef> pages; diff --git a/WebKitTools/WebKitTestRunner/InjectedBundle/InjectedBundle.h b/WebKitTools/WebKitTestRunner/InjectedBundle/InjectedBundle.h index ba021b1..d094f42 100644 --- a/WebKitTools/WebKitTestRunner/InjectedBundle/InjectedBundle.h +++ b/WebKitTools/WebKitTestRunner/InjectedBundle/InjectedBundle.h @@ -61,6 +61,8 @@ public: void done(); std::ostringstream& os() { return m_outputStream; } + bool isTestRunning() { return m_state == Testing; } + private: InjectedBundle(); ~InjectedBundle(); @@ -73,7 +75,7 @@ private: void willDestroyPage(WKBundlePageRef page); void didReceiveMessage(WKStringRef messageName, WKTypeRef messageBody); - void reset(); + void beginTesting(); WKBundleRef m_bundle; HashMap<WKBundlePageRef, InjectedBundlePage*> m_otherPages; @@ -84,6 +86,12 @@ private: RefPtr<EventSendingController> m_eventSendingController; std::ostringstream m_outputStream; + + enum State { + Idle, + Testing + }; + State m_state; }; } // namespace WTR diff --git a/WebKitTools/WebKitTestRunner/InjectedBundle/InjectedBundlePage.cpp b/WebKitTools/WebKitTestRunner/InjectedBundle/InjectedBundlePage.cpp index 40a098e..424f7ab 100644 --- a/WebKitTools/WebKitTestRunner/InjectedBundle/InjectedBundlePage.cpp +++ b/WebKitTools/WebKitTestRunner/InjectedBundle/InjectedBundlePage.cpp @@ -147,6 +147,12 @@ InjectedBundlePage::~InjectedBundlePage() { } +void InjectedBundlePage::stopLoading() +{ + WKBundlePageStopLoading(m_page); + m_isLoading = false; +} + void InjectedBundlePage::reset() { WKBundlePageClearMainFrameName(m_page); @@ -235,6 +241,9 @@ void InjectedBundlePage::didRunInsecureContentForFrame(WKBundlePageRef page, WKB void InjectedBundlePage::didStartProvisionalLoadForFrame(WKBundleFrameRef frame) { + if (!InjectedBundle::shared().isTestRunning()) + return; + if (frame == WKBundlePageGetMainFrame(m_page)) m_isLoading = true; } @@ -331,6 +340,8 @@ void InjectedBundlePage::dumpAllFramesText() void InjectedBundlePage::dump() { + ASSERT(InjectedBundle::shared().isTestRunning()); + InjectedBundle::shared().layoutTestController()->invalidateWaitToDumpWatchdog(); switch (InjectedBundle::shared().layoutTestController()->whatToDump()) { @@ -357,6 +368,9 @@ void InjectedBundlePage::dump() void InjectedBundlePage::didFinishLoadForFrame(WKBundleFrameRef frame) { + if (!InjectedBundle::shared().isTestRunning()) + return; + if (!WKBundleFrameIsMainFrame(frame)) return; @@ -373,6 +387,9 @@ void InjectedBundlePage::didFinishLoadForFrame(WKBundleFrameRef frame) void InjectedBundlePage::didFailLoadWithErrorForFrame(WKBundleFrameRef frame) { + if (!InjectedBundle::shared().isTestRunning()) + return; + if (!WKBundleFrameIsMainFrame(frame)) return; @@ -386,6 +403,9 @@ void InjectedBundlePage::didFailLoadWithErrorForFrame(WKBundleFrameRef frame) void InjectedBundlePage::didReceiveTitleForFrame(WKStringRef title, WKBundleFrameRef frame) { + if (!InjectedBundle::shared().isTestRunning()) + return; + if (!InjectedBundle::shared().layoutTestController()->shouldDumpTitleChanges()) return; @@ -394,6 +414,9 @@ void InjectedBundlePage::didReceiveTitleForFrame(WKStringRef title, WKBundleFram void InjectedBundlePage::didClearWindowForFrame(WKBundleFrameRef frame, JSGlobalContextRef context, JSObjectRef window) { + if (!InjectedBundle::shared().isTestRunning()) + return; + JSValueRef exception = 0; InjectedBundle::shared().layoutTestController()->makeWindowObject(context, window, &exception); InjectedBundle::shared().gcController()->makeWindowObject(context, window, &exception); @@ -414,6 +437,9 @@ void InjectedBundlePage::didChangeLocationWithinPageForFrame(WKBundleFrameRef fr void InjectedBundlePage::didFinishDocumentLoadForFrame(WKBundleFrameRef frame) { + if (!InjectedBundle::shared().isTestRunning()) + return; + unsigned pendingFrameUnloadEvents = WKBundleFrameGetPendingUnloadCount(frame); if (pendingFrameUnloadEvents) InjectedBundle::shared().os() << frame << " - has " << pendingFrameUnloadEvents << " onunload handler(s)\n"; @@ -460,12 +486,18 @@ void InjectedBundlePage::willRunJavaScriptPrompt(WKBundlePageRef page, WKStringR void InjectedBundlePage::willAddMessageToConsole(WKStringRef message, uint32_t lineNumber) { + if (!InjectedBundle::shared().isTestRunning()) + return; + // FIXME: Strip file: urls. InjectedBundle::shared().os() << "CONSOLE MESSAGE: line " << lineNumber << ": " << message << "\n"; } void InjectedBundlePage::willSetStatusbarText(WKStringRef statusbarText) { + if (!InjectedBundle::shared().isTestRunning()) + return; + if (!InjectedBundle::shared().layoutTestController()->shouldDumpStatusCallbacks()) return; @@ -474,11 +506,17 @@ void InjectedBundlePage::willSetStatusbarText(WKStringRef statusbarText) void InjectedBundlePage::willRunJavaScriptAlert(WKStringRef message, WKBundleFrameRef) { + if (!InjectedBundle::shared().isTestRunning()) + return; + InjectedBundle::shared().os() << "ALERT: " << message << "\n"; } void InjectedBundlePage::willRunJavaScriptConfirm(WKStringRef message, WKBundleFrameRef) { + if (!InjectedBundle::shared().isTestRunning()) + return; + InjectedBundle::shared().os() << "CONFIRM: " << message << "\n"; } @@ -546,6 +584,9 @@ void InjectedBundlePage::didChangeSelection(WKBundlePageRef page, WKStringRef no bool InjectedBundlePage::shouldBeginEditing(WKBundleRangeRef range) { + if (!InjectedBundle::shared().isTestRunning()) + return true; + if (InjectedBundle::shared().layoutTestController()->shouldDumpEditingCallbacks()) InjectedBundle::shared().os() << "EDITING DELEGATE: shouldBeginEditingInDOMRange:" << range << "\n"; return InjectedBundle::shared().layoutTestController()->shouldAllowEditing(); @@ -553,6 +594,9 @@ bool InjectedBundlePage::shouldBeginEditing(WKBundleRangeRef range) bool InjectedBundlePage::shouldEndEditing(WKBundleRangeRef range) { + if (!InjectedBundle::shared().isTestRunning()) + return true; + if (InjectedBundle::shared().layoutTestController()->shouldDumpEditingCallbacks()) InjectedBundle::shared().os() << "EDITING DELEGATE: shouldEndEditingInDOMRange:" << range << "\n"; return InjectedBundle::shared().layoutTestController()->shouldAllowEditing(); @@ -560,6 +604,9 @@ bool InjectedBundlePage::shouldEndEditing(WKBundleRangeRef range) bool InjectedBundlePage::shouldInsertNode(WKBundleNodeRef node, WKBundleRangeRef rangeToReplace, WKInsertActionType action) { + if (!InjectedBundle::shared().isTestRunning()) + return true; + static const char* insertactionstring[] = { "WebViewInsertActionTyped", "WebViewInsertActionPasted", @@ -573,6 +620,9 @@ bool InjectedBundlePage::shouldInsertNode(WKBundleNodeRef node, WKBundleRangeRef bool InjectedBundlePage::shouldInsertText(WKStringRef text, WKBundleRangeRef rangeToReplace, WKInsertActionType action) { + if (!InjectedBundle::shared().isTestRunning()) + return true; + static const char *insertactionstring[] = { "WebViewInsertActionTyped", "WebViewInsertActionPasted", @@ -586,6 +636,9 @@ bool InjectedBundlePage::shouldInsertText(WKStringRef text, WKBundleRangeRef ran bool InjectedBundlePage::shouldDeleteRange(WKBundleRangeRef range) { + if (!InjectedBundle::shared().isTestRunning()) + return true; + if (InjectedBundle::shared().layoutTestController()->shouldDumpEditingCallbacks()) InjectedBundle::shared().os() << "EDITING DELEGATE: shouldDeleteDOMRange:" << range << "\n"; return InjectedBundle::shared().layoutTestController()->shouldAllowEditing(); @@ -593,6 +646,9 @@ bool InjectedBundlePage::shouldDeleteRange(WKBundleRangeRef range) bool InjectedBundlePage::shouldChangeSelectedRange(WKBundleRangeRef fromRange, WKBundleRangeRef toRange, WKAffinityType affinity, bool stillSelecting) { + if (!InjectedBundle::shared().isTestRunning()) + return true; + static const char *affinitystring[] = { "NSSelectionAffinityUpstream", "NSSelectionAffinityDownstream" @@ -609,6 +665,9 @@ bool InjectedBundlePage::shouldChangeSelectedRange(WKBundleRangeRef fromRange, W bool InjectedBundlePage::shouldApplyStyle(WKBundleCSSStyleDeclarationRef style, WKBundleRangeRef range) { + if (!InjectedBundle::shared().isTestRunning()) + return true; + if (InjectedBundle::shared().layoutTestController()->shouldDumpEditingCallbacks()) InjectedBundle::shared().os() << "EDITING DELEGATE: shouldApplyStyle:" << style << " toElementsInDOMRange:" << range << "\n"; return InjectedBundle::shared().layoutTestController()->shouldAllowEditing(); @@ -616,27 +675,38 @@ bool InjectedBundlePage::shouldApplyStyle(WKBundleCSSStyleDeclarationRef style, void InjectedBundlePage::didBeginEditing(WKStringRef notificationName) { + if (!InjectedBundle::shared().isTestRunning()) + return; + if (InjectedBundle::shared().layoutTestController()->shouldDumpEditingCallbacks()) InjectedBundle::shared().os() << "EDITING DELEGATE: webViewDidBeginEditing:" << notificationName << "\n"; } void InjectedBundlePage::didEndEditing(WKStringRef notificationName) { + if (!InjectedBundle::shared().isTestRunning()) + return; + if (InjectedBundle::shared().layoutTestController()->shouldDumpEditingCallbacks()) InjectedBundle::shared().os() << "EDITING DELEGATE: webViewDidEndEditing:" << notificationName << "\n"; } void InjectedBundlePage::didChange(WKStringRef notificationName) { + if (!InjectedBundle::shared().isTestRunning()) + return; + if (InjectedBundle::shared().layoutTestController()->shouldDumpEditingCallbacks()) InjectedBundle::shared().os() << "EDITING DELEGATE: webViewDidChange:" << notificationName << "\n"; } void InjectedBundlePage::didChangeSelection(WKStringRef notificationName) { + if (!InjectedBundle::shared().isTestRunning()) + return; + if (InjectedBundle::shared().layoutTestController()->shouldDumpEditingCallbacks()) InjectedBundle::shared().os() << "EDITING DELEGATE: webViewDidChangeSelection:" << notificationName << "\n"; } - } // namespace WTR diff --git a/WebKitTools/WebKitTestRunner/InjectedBundle/InjectedBundlePage.h b/WebKitTools/WebKitTestRunner/InjectedBundle/InjectedBundlePage.h index 8909883..3f63bf3 100644 --- a/WebKitTools/WebKitTestRunner/InjectedBundle/InjectedBundlePage.h +++ b/WebKitTools/WebKitTestRunner/InjectedBundle/InjectedBundlePage.h @@ -38,6 +38,7 @@ public: WKBundlePageRef page() const { return m_page; } void dump(); + void stopLoading(); bool isLoading() { return m_isLoading; } void reset(); diff --git a/WebKitTools/WebKitTestRunner/PlatformWebView.h b/WebKitTools/WebKitTestRunner/PlatformWebView.h index 6fc4509..29c63ae 100644 --- a/WebKitTools/WebKitTestRunner/PlatformWebView.h +++ b/WebKitTools/WebKitTestRunner/PlatformWebView.h @@ -51,6 +51,7 @@ public: WKPageRef page(); PlatformWKView platformView() { return m_view; } void resizeTo(unsigned width, unsigned height); + void focus(); private: PlatformWKView m_view; diff --git a/WebKitTools/WebKitTestRunner/StringFunctions.h b/WebKitTools/WebKitTestRunner/StringFunctions.h index 4f8fe93..8195606 100644 --- a/WebKitTools/WebKitTestRunner/StringFunctions.h +++ b/WebKitTools/WebKitTestRunner/StringFunctions.h @@ -52,6 +52,16 @@ inline RetainPtr<CFStringRef> toCF(WKStringRef string) return RetainPtr<CFStringRef>(AdoptCF, WKStringCopyCFString(0, string)); } +inline RetainPtr<CFURLRef> toCF(WKURLRef url) +{ + return RetainPtr<CFURLRef>(AdoptCF, WKURLCopyCFURL(0, url)); +} + +inline RetainPtr<CFURLRef> toCF(const WKRetainPtr<WKURLRef>& url) +{ + return toCF(url.get()); +} + inline WKRetainPtr<WKStringRef> toWK(JSStringRef string) { return WKRetainPtr<WKStringRef>(AdoptWK, WKStringCreateWithCFString(toCF(string).get())); diff --git a/WebKitTools/WebKitTestRunner/TestController.cpp b/WebKitTools/WebKitTestRunner/TestController.cpp index 93857a7..c8a78d5 100644 --- a/WebKitTools/WebKitTestRunner/TestController.cpp +++ b/WebKitTools/WebKitTestRunner/TestController.cpp @@ -26,8 +26,10 @@ #include "TestController.h" #include "PlatformWebView.h" +#include "StringFunctions.h" #include "TestInvocation.h" #include <WebKit2/WKContextPrivate.h> +#include <WebKit2/WKPreferencesPrivate.h> #include <wtf/PassOwnPtr.h> namespace WTR { @@ -45,6 +47,8 @@ TestController::TestController(int argc, const char* argv[]) , m_verbose(false) , m_printSeparators(false) , m_usingServerMode(false) + , m_state(Initial) + , m_doneResetting(false) { initialize(argc, argv); controller = this; @@ -78,6 +82,7 @@ static WKPageRef createOtherPage(WKPageRef oldPage, const void*) closeOtherPage, 0, 0, + 0, 0 }; WKPageSetPageUIClient(newPage, &otherPageUIClient); @@ -119,6 +124,7 @@ void TestController::initialize(int argc, const char* argv[]) initializeTestPluginDirectory(); m_context.adopt(WKContextCreateWithInjectedBundlePath(injectedBundlePath())); + platformInitializeContext(); WKContextInjectedBundleClient injectedBundleClient = { 0, @@ -128,7 +134,7 @@ void TestController::initialize(int argc, const char* argv[]) WKContextSetInjectedBundleClient(m_context.get(), &injectedBundleClient); _WKContextSetAdditionalPluginsDirectory(m_context.get(), testPluginDirectory()); - + m_pageNamespace.adopt(WKPageNamespaceCreate(m_context.get())); m_mainWebView = adoptPtr(new PlatformWebView(m_pageNamespace.get())); @@ -140,13 +146,60 @@ void TestController::initialize(int argc, const char* argv[]) 0, 0, 0, + 0, 0 }; WKPageSetPageUIClient(m_mainWebView->page(), &pageUIClient); + + WKPageLoaderClient pageLoaderClient = { + 0, + this, + 0, + 0, + 0, + 0, + didFinishLoadForFrame, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + }; + WKPageSetPageLoaderClient(m_mainWebView->page(), &pageLoaderClient); +} + +void TestController::resetStateToConsistentValues() +{ + m_state = Resetting; + + // FIXME: This function should also ensure that there is only one page open. + + // Reset preferences + WKPreferencesRef preferences = WKContextGetPreferences(m_context.get()); + WKPreferencesSetOfflineWebApplicationCacheEnabled(preferences, true); + WKPreferencesSetFontSmoothingLevel(preferences, kWKFontSmoothingLevelNoSubpixelAntiAliasing); + + m_mainWebView->focus(); + + // Reset main page back to about:blank + m_doneResetting = false; + + WKRetainPtr<WKURLRef> url(AdoptWK, createWKURL("about:blank")); + WKPageLoadURL(m_mainWebView->page(), url.get()); + TestController::runUntil(m_doneResetting); } void TestController::runTest(const char* test) { + resetStateToConsistentValues(); + + m_state = RunningTest; m_currentInvocation.set(new TestInvocation(test)); m_currentInvocation->invoke(); m_currentInvocation.clear(); @@ -177,6 +230,8 @@ void TestController::run() } } +// WKContextInjectedBundleClient + void TestController::didReceiveMessageFromInjectedBundle(WKContextRef context, WKStringRef messageName, WKTypeRef messageBody, const void *clientInfo) { static_cast<TestController*>(const_cast<void*>(clientInfo))->didReceiveMessageFromInjectedBundle(messageName, messageBody); @@ -187,4 +242,28 @@ void TestController::didReceiveMessageFromInjectedBundle(WKStringRef messageName m_currentInvocation->didReceiveMessageFromInjectedBundle(messageName, messageBody); } +// WKPageLoaderClient + +void TestController::didFinishLoadForFrame(WKPageRef page, WKFrameRef frame, const void* clientInfo) +{ + static_cast<TestController*>(const_cast<void*>(clientInfo))->didFinishLoadForFrame(page, frame); +} + +void TestController::didFinishLoadForFrame(WKPageRef page, WKFrameRef frame) +{ + if (m_state != Resetting) + return; + + if (!WKFrameIsMainFrame(frame)) + return; + + WKRetainPtr<WKURLRef> wkURL(AdoptWK, WKFrameCopyURL(frame)); + RetainPtr<CFURLRef> cfURL= toCF(wkURL); + CFStringRef cfURLString = CFURLGetString(cfURL.get()); + if (!CFEqual(cfURLString, CFSTR("about:blank"))) + return; + + m_doneResetting = true; +} + } // namespace WTR diff --git a/WebKitTools/WebKitTestRunner/TestController.h b/WebKitTools/WebKitTestRunner/TestController.h index 5754728..5f6d99d 100644 --- a/WebKitTools/WebKitTestRunner/TestController.h +++ b/WebKitTools/WebKitTestRunner/TestController.h @@ -53,6 +53,9 @@ public: WKPageNamespaceRef pageNamespace() { return m_pageNamespace.get(); } WKContextRef context() { return m_context.get(); } + // Helper + static void runUntil(bool& done); + private: void initialize(int argc, const char* argv[]); void run(); @@ -61,13 +64,21 @@ private: void runTest(const char* pathOrURL); void platformInitialize(); + void platformInitializeContext(); void initializeInjectedBundlePath(); void initializeTestPluginDirectory(); + void resetStateToConsistentValues(); + // WKContextInjectedBundleClient static void didReceiveMessageFromInjectedBundle(WKContextRef context, WKStringRef messageName, WKTypeRef messageBody, const void*); void didReceiveMessageFromInjectedBundle(WKStringRef messageName, WKTypeRef messageBody); + // WKPageLoaderClient + static void didFinishLoadForFrame(WKPageRef page, WKFrameRef frame, const void*); + void didFinishLoadForFrame(WKPageRef page, WKFrameRef frame); + + OwnPtr<TestInvocation> m_currentInvocation; bool m_dumpPixels; @@ -81,6 +92,14 @@ private: OwnPtr<PlatformWebView> m_mainWebView; WKRetainPtr<WKContextRef> m_context; WKRetainPtr<WKPageNamespaceRef> m_pageNamespace; + + enum State { + Initial, + Resetting, + RunningTest + }; + State m_state; + bool m_doneResetting; }; } // namespace WTR diff --git a/WebKitTools/WebKitTestRunner/TestInvocation.cpp b/WebKitTools/WebKitTestRunner/TestInvocation.cpp index 9a0f0aa..47df66b 100644 --- a/WebKitTools/WebKitTestRunner/TestInvocation.cpp +++ b/WebKitTools/WebKitTestRunner/TestInvocation.cpp @@ -29,7 +29,6 @@ #include "StringFunctions.h" #include "TestController.h" #include <WebKit2/WKContextPrivate.h> -#include <WebKit2/WKPreferencesPrivate.h> #include <WebKit2/WKRetainPtr.h> #include <wtf/RetainPtr.h> @@ -59,7 +58,7 @@ static const unsigned normalHeight = 600; static void sizeWebViewForCurrentTest(char* pathOrURL) { - bool isSVGW3CTest = strstr(pathOrURL, "svg/W3C-SVG-1.1"); + bool isSVGW3CTest = strstr(pathOrURL, "svg/W3C-SVG-1.1") || strstr(pathOrURL, "svg\\W3C-SVG-1.1"); if (isSVGW3CTest) TestController::shared().mainWebView()->resizeTo(w3cSVGWidth, w3cSVGHeight); @@ -67,23 +66,15 @@ static void sizeWebViewForCurrentTest(char* pathOrURL) TestController::shared().mainWebView()->resizeTo(normalWidth, normalHeight); } -void TestInvocation::resetPreferencesToConsistentValues() -{ - WKPreferencesRef preferences = WKContextGetPreferences(TestController::shared().context()); - WKPreferencesSetOfflineWebApplicationCacheEnabled(preferences, true); - WKPreferencesSetFontSmoothingLevel(preferences, kWKFontSmoothingLevelNoSubpixelAntiAliasing); -} - void TestInvocation::invoke() { sizeWebViewForCurrentTest(m_pathOrURL); - resetPreferencesToConsistentValues(); WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithCFString(CFSTR("BeginTest"))); WKRetainPtr<WKStringRef> messageBody(AdoptWK, WKStringCreateWithCFString(CFSTR(""))); WKContextPostMessageToInjectedBundle(TestController::shared().context(), messageName.get(), messageBody.get()); - runUntil(m_gotInitialResponse); + TestController::runUntil(m_gotInitialResponse); if (m_error) { dump("FAIL\n"); return; @@ -91,7 +82,7 @@ void TestInvocation::invoke() WKPageLoadURL(TestController::shared().mainWebView()->page(), m_url.get()); - runUntil(m_gotFinalMessage); + TestController::runUntil(m_gotFinalMessage); if (m_error) { dump("FAIL\n"); return; diff --git a/WebKitTools/WebKitTestRunner/TestInvocation.h b/WebKitTools/WebKitTestRunner/TestInvocation.h index 484e61d..1b33e49 100644 --- a/WebKitTools/WebKitTestRunner/TestInvocation.h +++ b/WebKitTools/WebKitTestRunner/TestInvocation.h @@ -42,11 +42,6 @@ public: private: void dump(const char*); - void resetPreferencesToConsistentValues(); - - // Helper - static void runUntil(bool& done); - WKRetainPtr<WKURLRef> m_url; char* m_pathOrURL; diff --git a/WebKitTools/WebKitTestRunner/WebKitTestRunner.xcodeproj/project.pbxproj b/WebKitTools/WebKitTestRunner/WebKitTestRunner.xcodeproj/project.pbxproj index 6f78289..f5ee6d5 100644 --- a/WebKitTools/WebKitTestRunner/WebKitTestRunner.xcodeproj/project.pbxproj +++ b/WebKitTools/WebKitTestRunner/WebKitTestRunner.xcodeproj/project.pbxproj @@ -53,7 +53,6 @@ BCC997A511D3C8F60017BCA2 /* InjectedBundlePage.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BCC997A211D3C8F60017BCA2 /* InjectedBundlePage.cpp */; }; BCC9981811D3F51E0017BCA2 /* LayoutTestController.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BCC9981711D3F51E0017BCA2 /* LayoutTestController.cpp */; }; BCD7D2F811921278006DB7EE /* TestInvocation.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BCD7D2F711921278006DB7EE /* TestInvocation.cpp */; }; - BCDA2ABF1190B51A00C3BC47 /* TestInvocationMac.mm in Sources */ = {isa = PBXBuildFile; fileRef = BCDA2ABE1190B51A00C3BC47 /* TestInvocationMac.mm */; }; BCDA2B9A1191051F00C3BC47 /* JavaScriptCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = BCDA2B991191051F00C3BC47 /* JavaScriptCore.framework */; }; /* End PBXBuildFile section */ @@ -132,7 +131,6 @@ BCC9981711D3F51E0017BCA2 /* LayoutTestController.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = LayoutTestController.cpp; sourceTree = "<group>"; }; BCD7D2F611921278006DB7EE /* TestInvocation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TestInvocation.h; sourceTree = "<group>"; }; BCD7D2F711921278006DB7EE /* TestInvocation.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = TestInvocation.cpp; sourceTree = "<group>"; }; - BCDA2ABE1190B51A00C3BC47 /* TestInvocationMac.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = TestInvocationMac.mm; sourceTree = "<group>"; }; BCDA2B991191051F00C3BC47 /* JavaScriptCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = JavaScriptCore.framework; sourceTree = BUILT_PRODUCTS_DIR; }; /* End PBXFileReference section */ @@ -270,7 +268,6 @@ children = ( BC7933FF118F7C84005EA8E2 /* main.mm */, BC7934E711906846005EA8E2 /* PlatformWebViewMac.mm */, - BCDA2ABE1190B51A00C3BC47 /* TestInvocationMac.mm */, BC8C795B11D2785D004535A1 /* TestControllerMac.mm */, ); path = mac; @@ -426,7 +423,6 @@ BC793400118F7C84005EA8E2 /* main.mm in Sources */, BC793431118F7F19005EA8E2 /* TestController.cpp in Sources */, BC7934E811906846005EA8E2 /* PlatformWebViewMac.mm in Sources */, - BCDA2ABF1190B51A00C3BC47 /* TestInvocationMac.mm in Sources */, BCD7D2F811921278006DB7EE /* TestInvocation.cpp in Sources */, BC8C795C11D2785D004535A1 /* TestControllerMac.mm in Sources */, ); diff --git a/WebKitTools/WebKitTestRunner/mac/PlatformWebViewMac.mm b/WebKitTools/WebKitTestRunner/mac/PlatformWebViewMac.mm index 4e2a60c..96e6526 100644 --- a/WebKitTools/WebKitTestRunner/mac/PlatformWebViewMac.mm +++ b/WebKitTools/WebKitTestRunner/mac/PlatformWebViewMac.mm @@ -58,4 +58,9 @@ WKPageRef PlatformWebView::page() return [m_view pageRef]; } +void PlatformWebView::focus() +{ + // Implement. +} + } // namespace WTR diff --git a/WebKitTools/WebKitTestRunner/mac/TestControllerMac.mm b/WebKitTools/WebKitTestRunner/mac/TestControllerMac.mm index 1a71b5d..dbe35e2 100644 --- a/WebKitTools/WebKitTestRunner/mac/TestControllerMac.mm +++ b/WebKitTools/WebKitTestRunner/mac/TestControllerMac.mm @@ -45,4 +45,14 @@ void TestController::initializeTestPluginDirectory() m_testPluginDirectory.adopt(WKStringCreateWithCFString((CFStringRef)[[NSBundle mainBundle] bundlePath])); } +void TestController::runUntil(bool& done) +{ + while (!done) + [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]]; +} + +void TestController::platformInitializeContext() +{ +} + } // namespace WTR diff --git a/WebKitTools/WebKitTestRunner/mac/TestInvocationMac.mm b/WebKitTools/WebKitTestRunner/mac/TestInvocationMac.mm deleted file mode 100644 index bd01029..0000000 --- a/WebKitTools/WebKitTestRunner/mac/TestInvocationMac.mm +++ /dev/null @@ -1,36 +0,0 @@ -/* - * 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 "TestInvocation.h" - -namespace WTR { - -void TestInvocation::runUntil(bool& done) -{ - while (!done) - [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]]; -} - -} // namespace WTR diff --git a/WebKitTools/WebKitTestRunner/win/PlatformWebViewWin.cpp b/WebKitTools/WebKitTestRunner/win/PlatformWebViewWin.cpp index e602d0e..deed4ab 100644 --- a/WebKitTools/WebKitTestRunner/win/PlatformWebViewWin.cpp +++ b/WebKitTools/WebKitTestRunner/win/PlatformWebViewWin.cpp @@ -65,7 +65,7 @@ PlatformWebView::~PlatformWebView() void PlatformWebView::resizeTo(unsigned width, unsigned height) { - // Implement + ::SetWindowPos(WKViewGetWindow(m_view), 0, 0, 0, width, height, SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOCOPYBITS); } WKPageRef PlatformWebView::page() @@ -73,4 +73,9 @@ WKPageRef PlatformWebView::page() return WKViewGetPage(m_view); } +void PlatformWebView::focus() +{ + ::SetFocus(::WKViewGetWindow(m_view)); +} + } // namespace WTR diff --git a/WebKitTools/WebKitTestRunner/win/TestControllerWin.cpp b/WebKitTools/WebKitTestRunner/win/TestControllerWin.cpp index f650d7f..e35ee22 100644 --- a/WebKitTools/WebKitTestRunner/win/TestControllerWin.cpp +++ b/WebKitTools/WebKitTestRunner/win/TestControllerWin.cpp @@ -29,6 +29,7 @@ #include <io.h> #include <shlwapi.h> #include <string> +#include <WebKit2/WKContextPrivateWin.h> #include <WebKit2/WKStringCF.h> #include <wtf/RetainPtr.h> #include <wtf/Vector.h> @@ -80,8 +81,17 @@ static void addQTDirToPATH() ::SetEnvironmentVariableW(pathEnvironmentVariable, newPath.data()); } +static LONG WINAPI exceptionFilter(EXCEPTION_POINTERS*) +{ + fputs("#CRASHED\n", stderr); + fflush(stderr); + return EXCEPTION_CONTINUE_SEARCH; +} + void TestController::platformInitialize() { + ::SetUnhandledExceptionFilter(exceptionFilter); + _setmode(1, _O_BINARY); _setmode(2, _O_BINARY); @@ -113,4 +123,22 @@ void TestController::initializeTestPluginDirectory() m_testPluginDirectory.adopt(WKStringCreateWithCFString(testPluginDirectoryPath.get())); } +void TestController::runUntil(bool& done) +{ + while (!done) { + MSG msg; + BOOL result = GetMessage(&msg, 0, 0, 0); + if (result == -1) + return; + TranslateMessage(&msg); + DispatchMessage(&msg); + } +} + +void TestController::platformInitializeContext() +{ + // FIXME: Make DRT pass with Windows native controls. <http://webkit.org/b/25592> + WKContextSetShouldPaintNativeControls(m_context.get(), false); +} + } // namespace WTR diff --git a/WebKitTools/WebKitTestRunner/win/TestInvocationWin.cpp b/WebKitTools/WebKitTestRunner/win/TestInvocationWin.cpp deleted file mode 100644 index cfeebcc..0000000 --- a/WebKitTools/WebKitTestRunner/win/TestInvocationWin.cpp +++ /dev/null @@ -1,42 +0,0 @@ -/* - * 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 "TestInvocation.h" - -namespace WTR { - -void TestInvocation::runUntil(bool& done) -{ - while (!done) { - MSG msg; - BOOL result = GetMessage(&msg, 0, 0, 0); - if (result == -1) - return; - TranslateMessage(&msg); - DispatchMessage(&msg); - } -} - -} // namespace WTR diff --git a/WebKitTools/WebKitTestRunner/win/WebKitTestRunner.vcproj b/WebKitTools/WebKitTestRunner/win/WebKitTestRunner.vcproj index 7375bd4..d7ddd5c 100644 --- a/WebKitTools/WebKitTestRunner/win/WebKitTestRunner.vcproj +++ b/WebKitTools/WebKitTestRunner/win/WebKitTestRunner.vcproj @@ -317,10 +317,6 @@ RelativePath=".\TestControllerWin.cpp"
>
</File>
- <File
- RelativePath=".\TestInvocationWin.cpp"
- >
- </File>
</Filter>
<File
RelativePath="..\PlatformWebView.h"
diff --git a/WebKitTools/gdb/webcore.py b/WebKitTools/gdb/webcore.py index 83886f8..8dc4d8e 100644 --- a/WebKitTools/gdb/webcore.py +++ b/WebKitTools/gdb/webcore.py @@ -26,170 +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. -"""GDB support for WebKit types. - -Add this to your gdb by amending your ~/.gdbinit as follows: - python - import sys - sys.path.insert(0, "/path/to/tools/gdb/") - import webcore -""" - -import gdb -import struct - -def ustring_to_string(ptr, length=None): - """Convert a pointer to UTF-16 data into a Python Unicode string. - - ptr and length are both gdb.Value objects. - If length is unspecified, will guess at the length.""" - extra = '' - if length is None: - # Try to guess at the length. - for i in xrange(0, 2048): - if int((ptr + i).dereference()) == 0: - length = i - break - if length is None: - length = 256 - extra = u' (no trailing NUL found)' - else: - length = int(length) - - char_vals = [int((ptr + i).dereference()) for i in xrange(length)] - string = struct.pack('H' * length, *char_vals).decode('utf-16', 'replace') - - return string + extra - - -class StringPrinter(object): - "Shared code between different string-printing classes" - def __init__(self, val): - self.val = val - - def display_hint(self): - return 'string' - - -class UCharStringPrinter(StringPrinter): - "Print a UChar*; we must guess at the length" - def to_string(self): - return ustring_to_string(self.val) - - -class WebCoreAtomicStringPrinter(StringPrinter): - "Print a WebCore::AtomicString" - def to_string(self): - return self.val['m_string'] - - -class WebCoreStringPrinter(StringPrinter): - "Print a WebCore::String" - def get_length(self): - if not self.val['m_impl']['m_ptr']: - return 0 - return self.val['m_impl']['m_ptr']['m_length'] - - def to_string(self): - if self.get_length() == 0: - return '(null)' - - return ustring_to_string(self.val['m_impl']['m_ptr']['m_data'], - self.get_length()) - - -class WebCoreQualifiedNamePrinter(StringPrinter): - "Print a WebCore::QualifiedName" - - def __init__(self, val): - super(WebCoreQualifiedNamePrinter, self).__init__(val) - self.prefix_length = 0 - self.length = 0 - if self.val['m_impl']: - self.prefix_printer = WebCoreStringPrinter( - self.val['m_impl']['m_prefix']['m_string']) - self.local_name_printer = WebCoreStringPrinter( - self.val['m_impl']['m_localName']['m_string']) - self.prefix_length = self.prefix_printer.get_length() - if self.prefix_length > 0: - self.length = (self.prefix_length + 1 + - self.local_name_printer.get_length()) - else: - self.length = self.local_name_printer.get_length() - - def get_length(self): - return self.length - - def to_string(self): - if self.get_length() == 0: - return "(null)" - else: - if self.prefix_length > 0: - return (self.prefix_printer.to_string() + ":" + - self.local_name_printer.to_string()) - else: - return self.local_name_printer.to_string() - - - -def lookup_function(val): - """Function used to load pretty printers; will be passed to GDB.""" - lookup_tag = val.type.tag - printers = { - "WebCore::AtomicString": WebCoreAtomicStringPrinter, - "WebCore::String": WebCoreStringPrinter, - "WebCore::QualifiedName": WebCoreQualifiedNamePrinter, - } - name = val.type.tag - if name in printers: - return printers[name](val) - - if val.type.code == gdb.TYPE_CODE_PTR: - name = str(val.type.target().unqualified()) - if name == 'UChar': - return UCharStringPrinter(val) - - return None - - -gdb.pretty_printers.append(lookup_function) - - - -class PrintPathToRootCommand(gdb.Command): - """Command for printing WebKit Node trees. -Usage: printpathtoroot variable_name -""" - - def __init__(self): - super(PrintPathToRootCommand, self).__init__("printpathtoroot", - gdb.COMMAND_SUPPORT, - gdb.COMPLETE_NONE) - - def invoke(self, arg, from_tty): - element_type = gdb.lookup_type('WebCore::Element') - node_type = gdb.lookup_type('WebCore::Node') - frame = gdb.selected_frame() - try: - val = gdb.Frame.read_var(frame, arg) - except: - print "No such variable, or invalid type" - return - - target_type = str(val.type.target().strip_typedefs()) - if target_type == str(node_type): - stack = [] - while val: - stack.append([val, - val.cast(element_type.pointer()).dereference()['m_tagName']]) - val = val.dereference()['m_parent'] - - padding = '' - while len(stack) > 0: - pair = stack.pop() - print padding, pair[1], pair[0] - padding = padding + ' ' - else: - print 'Sorry: I don\'t know how to deal with %s yet.' % target_type - -PrintPathToRootCommand() +# For backward compatibility. +import webkit +print ("webcore.py is deprecated. Please use 'import webkit' instead of " + "'import webcore' in your ~/.gdbinit.") diff --git a/WebKitTools/gdb/webkit.py b/WebKitTools/gdb/webkit.py new file mode 100644 index 0000000..2d3b47a --- /dev/null +++ b/WebKitTools/gdb/webkit.py @@ -0,0 +1,272 @@ +# 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. + +"""GDB support for WebKit types. + +Add this to your gdb by amending your ~/.gdbinit as follows: + python + import sys + sys.path.insert(0, "/path/to/tools/gdb/") + import webkit +""" + +import gdb +import re +import struct + + +def ustring_to_string(ptr, length=None): + """Convert a pointer to UTF-16 data into a Python Unicode string. + + ptr and length are both gdb.Value objects. + If length is unspecified, will guess at the length.""" + extra = '' + if length is None: + # Try to guess at the length. + for i in xrange(0, 2048): + if int((ptr + i).dereference()) == 0: + length = i + break + if length is None: + length = 256 + extra = u' (no trailing NUL found)' + else: + length = int(length) + + char_vals = [int((ptr + i).dereference()) for i in xrange(length)] + string = struct.pack('H' * length, *char_vals).decode('utf-16', 'replace') + + return string + extra + + +class StringPrinter(object): + "Shared code between different string-printing classes" + def __init__(self, val): + self.val = val + + def display_hint(self): + return 'string' + + +class UCharStringPrinter(StringPrinter): + "Print a UChar*; we must guess at the length" + def to_string(self): + return ustring_to_string(self.val) + + +class WTFAtomicStringPrinter(StringPrinter): + "Print a WTF::AtomicString" + def to_string(self): + return self.val['m_string'] + + +class WTFStringPrinter(StringPrinter): + "Print a WTF::String" + def get_length(self): + if not self.val['m_impl']['m_ptr']: + return 0 + return self.val['m_impl']['m_ptr']['m_length'] + + def to_string(self): + if self.get_length() == 0: + return '(null)' + + return ustring_to_string(self.val['m_impl']['m_ptr']['m_data'], + self.get_length()) + + +class WebCoreQualifiedNamePrinter(StringPrinter): + "Print a WebCore::QualifiedName" + + def __init__(self, val): + super(WebCoreQualifiedNamePrinter, self).__init__(val) + self.prefix_length = 0 + self.length = 0 + if self.val['m_impl']: + self.prefix_printer = WTFStringPrinter( + self.val['m_impl']['m_prefix']['m_string']) + self.local_name_printer = WTFStringPrinter( + self.val['m_impl']['m_localName']['m_string']) + self.prefix_length = self.prefix_printer.get_length() + if self.prefix_length > 0: + self.length = (self.prefix_length + 1 + + self.local_name_printer.get_length()) + else: + self.length = self.local_name_printer.get_length() + + def get_length(self): + return self.length + + def to_string(self): + if self.get_length() == 0: + return "(null)" + else: + if self.prefix_length > 0: + return (self.prefix_printer.to_string() + ":" + + self.local_name_printer.to_string()) + else: + return self.local_name_printer.to_string() + + +class WTFVectorPrinter: + """Pretty Printer for a WTF::Vector. + + The output of this pretty printer is similar to the output of std::vector's + pretty printer, which is bundled in gcc. + + Example gdb session should look like: + (gdb) p v + $3 = WTF::Vector of length 7, capacity 16 = {7, 17, 27, 37, 47, 57, 67} + (gdb) set print elements 3 + (gdb) p v + $6 = WTF::Vector of length 7, capacity 16 = {7, 17, 27...} + (gdb) set print array + (gdb) p v + $7 = WTF::Vector of length 7, capacity 16 = { + 7, + 17, + 27 + ... + } + (gdb) set print elements 200 + (gdb) p v + $8 = WTF::Vector of length 7, capacity 16 = { + 7, + 17, + 27, + 37, + 47, + 57, + 67 + } + """ + + class Iterator: + def __init__(self, start, finish): + self.item = start + self.finish = finish + self.count = 0 + + def __iter__(self): + return self + + def next(self): + if self.item == self.finish: + raise StopIteration + count = self.count + self.count += 1 + element = self.item.dereference() + self.item += 1 + return ('[%d]' % count, element) + + def __init__(self, val): + self.val = val + + def children(self): + start = self.val['m_buffer']['m_buffer'] + return self.Iterator(start, start + self.val['m_size']) + + def to_string(self): + return ('%s of length %d, capacity %d' + % ('WTF::Vector', self.val['m_size'], self.val['m_buffer']['m_capacity'])) + + def display_hint(self): + return 'array' + + +def add_pretty_printers(): + pretty_printers_dict = { + re.compile("^WTF::Vector<.*>$"): WTFVectorPrinter, + re.compile("^WTF::AtomicString$"): WTFAtomicStringPrinter, + re.compile("^WTF::String$"): WTFStringPrinter, + re.compile("^WebCore::QualifiedName$"): WebCoreQualifiedNamePrinter, + } + + def lookup_function(val): + """Function used to load pretty printers; will be passed to GDB.""" + type = val.type + if type.code == gdb.TYPE_CODE_REF: + type = type.target() + type = type.unqualified().strip_typedefs() + typename = type.tag + if not typename: + return None + for function, pretty_printer in pretty_printers_dict.items(): + if function.search(typename): + return pretty_printer(val) + + if type.code == gdb.TYPE_CODE_PTR: + name = str(type.target().unqualified()) + if name == 'UChar': + return UCharStringPrinter(val) + return None + + gdb.pretty_printers.append(lookup_function) + + +add_pretty_printers() + + +class PrintPathToRootCommand(gdb.Command): + """Command for printing WebKit Node trees. + + Usage: printpathtoroot variable_name""" + + def __init__(self): + super(PrintPathToRootCommand, self).__init__("printpathtoroot", + gdb.COMMAND_SUPPORT, + gdb.COMPLETE_NONE) + + def invoke(self, arg, from_tty): + element_type = gdb.lookup_type('WebCore::Element') + node_type = gdb.lookup_type('WebCore::Node') + frame = gdb.selected_frame() + try: + val = gdb.Frame.read_var(frame, arg) + except: + print "No such variable, or invalid type" + return + + target_type = str(val.type.target().strip_typedefs()) + if target_type == str(node_type): + stack = [] + while val: + stack.append([val, + val.cast(element_type.pointer()).dereference()['m_tagName']]) + val = val.dereference()['m_parent'] + + padding = '' + while len(stack) > 0: + pair = stack.pop() + print padding, pair[1], pair[0] + padding = padding + ' ' + else: + print 'Sorry: I don\'t know how to deal with %s yet.' % target_type + + +PrintPathToRootCommand() diff --git a/WebKitTools/gdb/wtf.py b/WebKitTools/gdb/wtf.py deleted file mode 100644 index cf4b59b..0000000 --- a/WebKitTools/gdb/wtf.py +++ /dev/null @@ -1,133 +0,0 @@ -# Copyright (C) 2010, Google Inc. All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are -# met: -# -# * Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# * Redistributions in binary form must reproduce the above -# copyright notice, this list of conditions and the following disclaimer -# in the documentation and/or other materials provided with the -# distribution. -# * Neither the name of Google Inc. nor the names of its -# contributors may be used to endorse or promote products derived from -# this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -"""GDB support for WebKit WTF types. - -Add this to your gdb by amending your ~/.gdbinit as follows: - python - import sys - sys.path.insert(0, "/path/to/tools/gdb/") - import wtf - -See http://sourceware.org/gdb/current/onlinedocs/gdb/Python.html for GDB's -Python API. -""" - -import gdb -import re - - -class WTFVectorPrinter: - """Pretty Printer for a WTF::Vector. - - The output of this pretty printer is similar to the output of std::vector's - pretty printer, which is bundled in gcc. - - Example gdb session should look like: - (gdb) p v - $3 = WTF::Vector of length 7, capacity 16 = {7, 17, 27, 37, 47, 57, 67} - (gdb) set print elements 3 - (gdb) p v - $6 = WTF::Vector of length 7, capacity 16 = {7, 17, 27...} - (gdb) set print array - (gdb) p v - $7 = WTF::Vector of length 7, capacity 16 = { - 7, - 17, - 27 - ... - } - (gdb) set print elements 200 - (gdb) p v - $8 = WTF::Vector of length 7, capacity 16 = { - 7, - 17, - 27, - 37, - 47, - 57, - 67 - } - """ - - class Iterator: - def __init__(self, start, finish): - self.item = start - self.finish = finish - self.count = 0 - - def __iter__(self): - return self - - def next(self): - if self.item == self.finish: - raise StopIteration - count = self.count - self.count += 1 - element = self.item.dereference() - self.item += 1 - return ('[%d]' % count, element) - - def __init__(self, val): - self.val = val - - def children(self): - start = self.val['m_buffer']['m_buffer'] - return self.Iterator(start, start + self.val['m_size']) - - def to_string(self): - return ('%s of length %d, capacity %d' - % ('WTF::Vector', self.val['m_size'], self.val['m_buffer']['m_capacity'])) - - def display_hint(self): - return 'array' - - -def lookup_function(val): - type = val.type - if type.code == gdb.TYPE_CODE_REF: - type = type.target() - type = type.unqualified().strip_typedefs() - typename = type.tag - if not typename: - return None - for function, pretty_printer in pretty_printers_dict.items(): - if function.search(typename): - return pretty_printer(val) - return None - - -def build_pretty_printers_dict(): - pretty_printers_dict[re.compile('^WTF::Vector<.*>$')] = WTFVectorPrinter - - -pretty_printers_dict = {} - -build_pretty_printers_dict() - -gdb.pretty_printers.append(lookup_function) diff --git a/WebKitTools/wx/browser/wscript b/WebKitTools/wx/browser/wscript index bd2640c..8c22cf6 100644 --- a/WebKitTools/wx/browser/wscript +++ b/WebKitTools/wx/browser/wscript @@ -46,9 +46,9 @@ def build(bld): includes = ' '.join(include_paths), source = 'browser.cpp', target = 'wxBrowser', - uselib = 'WX CURL ICU XSLT XML WXWEBKIT ' + get_config(), + uselib = 'WX CURL ICU XSLT XML ' + get_config(), libpath = [output_dir], - uselib_local = '', + uselib_local = 'wxwebkit', install_path = output_dir) if sys.platform.startswith('darwin'): diff --git a/WebKitTools/wx/build/settings.py b/WebKitTools/wx/build/settings.py index be43873..74d9789 100644 --- a/WebKitTools/wx/build/settings.py +++ b/WebKitTools/wx/build/settings.py @@ -97,56 +97,56 @@ jscore_dirs = [ ] webcore_dirs = [ - 'accessibility', - 'bindings', - 'bindings/cpp', - 'bindings/generic', - 'bindings/js', - 'bridge', - 'bridge/c', - 'bridge/jsc', - 'css', - 'DerivedSources', - 'dom', - 'dom/default', - 'editing', - 'history', - 'html', - 'html/canvas', - 'inspector', - 'loader', - 'loader/appcache', - 'loader/archive', - 'loader/icon', - 'notifications', - 'page', - 'page/animation', - 'platform', - 'platform/animation', - 'platform/graphics', - 'platform/graphics/filters', - 'platform/graphics/transforms', - 'platform/image-decoders', - 'platform/image-decoders/bmp', - 'platform/image-decoders/gif', - 'platform/image-decoders/ico', - 'platform/image-decoders/jpeg', - 'platform/image-decoders/png', - 'platform/mock', - 'platform/network', - 'platform/sql', - 'platform/text', - 'platform/text/transcoder', - 'plugins', - 'rendering', - 'rendering/style', - 'storage', - 'svg', - 'svg/animation', - 'svg/graphics', - 'svg/graphics/filters', - 'websockets', - 'xml' + 'WebCore/accessibility', + 'WebCore/bindings', + 'WebCore/bindings/cpp', + 'WebCore/bindings/generic', + 'WebCore/bindings/js', + 'WebCore/bridge', + 'WebCore/bridge/c', + 'WebCore/bridge/jsc', + 'WebCore/css', + 'WebCore/DerivedSources', + 'WebCore/dom', + 'WebCore/dom/default', + 'WebCore/editing', + 'WebCore/history', + 'WebCore/html', + 'WebCore/html/canvas', + 'WebCore/inspector', + 'WebCore/loader', + 'WebCore/loader/appcache', + 'WebCore/loader/archive', + 'WebCore/loader/icon', + 'WebCore/notifications', + 'WebCore/page', + 'WebCore/page/animation', + 'WebCore/platform', + 'WebCore/platform/animation', + 'WebCore/platform/graphics', + 'WebCore/platform/graphics/filters', + 'WebCore/platform/graphics/transforms', + 'WebCore/platform/image-decoders', + 'WebCore/platform/image-decoders/bmp', + 'WebCore/platform/image-decoders/gif', + 'WebCore/platform/image-decoders/ico', + 'WebCore/platform/image-decoders/jpeg', + 'WebCore/platform/image-decoders/png', + 'WebCore/platform/mock', + 'WebCore/platform/network', + 'WebCore/platform/sql', + 'WebCore/platform/text', + 'WebCore/platform/text/transcoder', + 'WebCore/plugins', + 'WebCore/rendering', + 'WebCore/rendering/style', + 'WebCore/storage', + 'WebCore/svg', + 'WebCore/svg/animation', + 'WebCore/svg/graphics', + 'WebCore/svg/graphics/filters', + 'WebCore/websockets', + 'WebCore/xml' ] config = get_config(wk_root) @@ -180,7 +180,7 @@ os.environ['CREATE_HASH_TABLE'] = create_hash_table feature_defines = ['ENABLE_DATABASE', 'ENABLE_XSLT', 'ENABLE_JAVASCRIPT_DEBUGGER', 'ENABLE_SVG', 'ENABLE_SVG_USE', 'ENABLE_FILTERS', 'ENABLE_SVG_FONTS', 'ENABLE_SVG_ANIMATION', 'ENABLE_SVG_AS_IMAGE', 'ENABLE_SVG_FOREIGN_OBJECT', - 'ENABLE_JIT', 'ENABLE_EXECUTABLE_ALLOCATOR_DEMAND', 'BUILDING_%s' % build_port.upper()] + 'ENABLE_JIT', 'BUILDING_%s' % build_port.upper()] msvc_version = 'msvc2008' @@ -289,9 +289,6 @@ def common_configure(conf): conf.env.append_value('CXXDEFINES', ['BUILDING_WX__=1', 'JS_NO_EXPORT']) - conf.env['LIB_WXWEBKIT'] = ['wxwebkit'] - conf.env['CXXDEFINES_WXWEBKIT'] = ['WXUSINGDLL_WEBKIT'] - if building_on_win32: conf.env.append_value('LIBPATH', os.path.join(msvclibs_dir, 'lib')) # wx settings @@ -303,22 +300,8 @@ def common_configure(conf): conf.env['LIB_WX'] = wxlibs conf.env['LIBPATH_WX'] = wxlibpaths - if building_on_win32: - conf.env['LIB_JSCORE'] = [libprefix + 'jscore'] - conf.env['LIB_WEBCORE'] = [libprefix + 'webcore'] - elif sys.platform.startswith('darwin'): - conf.env['LINKFLAGS_JSCORE'] = ['-Wl,-force_load,%s' % os.path.join(output_dir, 'libjscore.a')] - conf.env['LINKFLAGS_WEBCORE'] = ['-Wl,-force_load,%s' % os.path.join(output_dir, 'libwebcore.a')] - else: - conf.env['LINKFLAGS_JSCORE'] = ['-Wl,-whole-archive', '-ljscore', '-Wl,-no-whole-archive'] - conf.env['LINKFLAGS_WEBCORE'] = ['-Wl,-whole-archive', '-lwebcore', '-Wl,-no-whole-archive'] - if sys.platform.startswith('darwin'): conf.env['LIB_ICU'] = ['icucore'] - # Apple does not ship the ICU headers with Mac OS X, so WebKit includes a copy of 3.2 headers - conf.env.append_value('CPPPATH_JSCORE', os.path.join(jscore_dir, 'icu')) - - conf.env.append_value('CPPPATH_WEBCORE', os.path.join(webcore_dir, 'icu')) conf.env.append_value('CPPPATH', wklibs_dir) conf.env.append_value('LIBPATH', wklibs_dir) @@ -340,12 +323,12 @@ def common_configure(conf): sdk_version = min_version if min_version == "10.4": sdk_version += "u" - conf.env.append_value('LIB_WEBCORE', ['WebKitSystemInterfaceTiger']) + conf.env.append_value('LIB_WKINTERFACE', ['WebKitSystemInterfaceTiger']) else: # NOTE: There is a WebKitSystemInterfaceSnowLeopard, but when we use that # on 10.6, we get a strange missing symbol error, and this library seems to # work fine for wx's purposes. - conf.env.append_value('LIB_WEBCORE', ['WebKitSystemInterfaceLeopard']) + conf.env.append_value('LIB_WKINTERFACE', ['WebKitSystemInterfaceLeopard']) sdkroot = '/Developer/SDKs/MacOSX%s.sdk' % sdk_version sdkflags = ['-arch', 'i386', '-isysroot', sdkroot] diff --git a/WebKitTools/wx/build/waf_extensions.py b/WebKitTools/wx/build/waf_extensions.py index 6816441..f50f264 100644 --- a/WebKitTools/wx/build/waf_extensions.py +++ b/WebKitTools/wx/build/waf_extensions.py @@ -35,7 +35,12 @@ def exec_command(s, **kw): if sys.platform.startswith('win') and len(' '.join(s)) > 32000: import tempfile (fd, filename) = tempfile.mkstemp() - os.write(fd, ' '.join(s[1:])) + t = [] + for i in s: + if i.find(" ") != -1: + i = '"%s"' % i + t.append(i) + os.write(fd, ' '.join(t[1:])) os.close(fd) s = [s[0], '@' + filename] |