diff options
author | Steve Block <steveblock@google.com> | 2010-04-27 16:23:55 +0100 |
---|---|---|
committer | Steve Block <steveblock@google.com> | 2010-04-27 17:07:03 +0100 |
commit | 692e5dbf12901edacf14812a6fae25462920af42 (patch) | |
tree | d62802373a429e0a9dc093b6046c166b2c514285 /WebKitTools | |
parent | e24bea4efef1c414137d36a9778aa4e142e10c7d (diff) | |
download | external_webkit-692e5dbf12901edacf14812a6fae25462920af42.zip external_webkit-692e5dbf12901edacf14812a6fae25462920af42.tar.gz external_webkit-692e5dbf12901edacf14812a6fae25462920af42.tar.bz2 |
Merge webkit.org at r55033 : Initial merge by git
Change-Id: I98a4af828067cc243ec3dc5e5826154dd88074b5
Diffstat (limited to 'WebKitTools')
54 files changed, 2523 insertions, 1106 deletions
diff --git a/WebKitTools/BuildSlaveSupport/build.webkit.org-config/config.json b/WebKitTools/BuildSlaveSupport/build.webkit.org-config/config.json index 69ff238..3477c97 100644 --- a/WebKitTools/BuildSlaveSupport/build.webkit.org-config/config.json +++ b/WebKitTools/BuildSlaveSupport/build.webkit.org-config/config.json @@ -24,6 +24,7 @@ { "name": "gtk-linux-slave-1", "platform": "gtk"}, { "name": "gtk-linux-slave-2", "platform": "gtk"}, { "name": "gtk-linux-slave-3", "platform": "gtk"}, + { "name": "gtk-linux-slave-4", "platform": "gtk"}, { "name": "szeged-linux-1", "platform": "qt"}, @@ -92,7 +93,7 @@ "slavenames": ["apple-windows-4", "apple-windows-3", "test-slave"] }, { - "name": "GTK Linux Release", "type": "BuildAndTest", "builddir": "gtk-linux-release", + "name": "GTK Linux 32-bit Release", "type": "BuildAndTest", "builddir": "gtk-linux-32-release", "platform": "gtk", "configuration": "release", "architectures": ["i386"], "slavenames": ["gtk-linux-slave-1"] }, @@ -107,6 +108,11 @@ "slavenames": ["gtk-linux-slave-3"] }, { + "name": "GTK Linux 64-bit Release", "type": "BuildAndTest", "builddir": "gtk-linux-64-release", + "platform": "gtk", "configuration": "release", "architectures": ["x86_64"], + "slavenames": ["gtk-linux-slave-4"] + }, + { "name": "Qt Linux Release", "type": "BuildAndTest", "builddir": "qt-linux-release", "platform": "qt", "configuration": "release", "architectures": ["i386"], "slavenames": ["szeged-linux-1"] @@ -132,7 +138,7 @@ "builderNames": ["Tiger Intel Release", "Leopard Intel Release (Build)", "Leopard Intel Debug (Build)", "SnowLeopard Intel Release (Build)", "SnowLeopard Intel Leaks", "Windows Release (Build)", "Windows Debug (Build)", - "GTK Linux Release", "GTK Linux 32-bit Debug", "GTK Linux 64-bit Debug", + "GTK Linux 32-bit Release", "GTK Linux 32-bit Debug", "GTK Linux 64-bit Debug", "GTK Linux 64-bit Release", "Qt Linux Release", "Chromium Win Release", "Chromium Mac Release", "Chromium Linux Release"] }, diff --git a/WebKitTools/BuildSlaveSupport/build.webkit.org-config/master.cfg b/WebKitTools/BuildSlaveSupport/build.webkit.org-config/master.cfg index cd81108..1823277 100644 --- a/WebKitTools/BuildSlaveSupport/build.webkit.org-config/master.cfg +++ b/WebKitTools/BuildSlaveSupport/build.webkit.org-config/master.cfg @@ -230,6 +230,42 @@ class RunWebKitTests(shell.Test): return [self.name] +class RunGtkAPITests(shell.Test): + name = "API tests" + description = ["API tests running"] + descriptionDone = ["API tests"] + command = ["perl", "./WebKitTools/Scripts/run-gtk-tests", WithProperties("--%(configuration)s")] + + def commandComplete(self, cmd): + shell.Test.commandComplete(self, cmd) + + logText = cmd.logs['stdio'].getText() + incorrectLines = [] + for line in logText.splitlines(): + if line.startswith('ERROR'): + incorrectLines.append(line) + + self.incorrectLines = incorrectLines + + def evaluateCommand(self, cmd): + if self.incorrectLines: + return FAILURE + + if cmd.rc != 0: + return FAILURE + + return SUCCESS + + def getText(self, cmd, results): + return self.getText2(cmd, results) + + def getText2(self, cmd, results): + if results != SUCCESS and self.incorrectLines: + return ["%d API tests failed" % self.incorrectLines] + + return [self.name] + + class RunWebKitLeakTests(RunWebKitTests): def start(self): self.setCommand(self.command + ["--leaks"]) @@ -312,6 +348,8 @@ class BuildAndTestFactory(Factory): self.addStep(ArchiveTestResults) self.addStep(UploadTestResults) self.addStep(ExtractTestResults) + if platform == "gtk": + self.addStep(RunGtkAPITests) class BuildAndTestLeaksFactory(BuildAndTestFactory): TestClass = RunWebKitLeakTests diff --git a/WebKitTools/ChangeLog b/WebKitTools/ChangeLog index ab4b32d..6a4b7b3 100644 --- a/WebKitTools/ChangeLog +++ b/WebKitTools/ChangeLog @@ -1,3 +1,593 @@ +2010-02-19 Jesus Sanchez-Palencia <jesus.palencia@openbossa.org> + + Reviewed by Kenneth Rohde Christiansen. + + [Qt] Need a final integration between QtLauncher and QGVLauncher + https://bugs.webkit.org/show_bug.cgi?id=35161 + + Add animated flip support to QtLauncher when running on QGraphicsView mode. + + * QtLauncher/main.cpp: + (LauncherWindow::initializeView): + (LauncherWindow::setupUI): + * QtLauncher/webview.cpp: + (WebViewGraphicsBased::WebViewGraphicsBased): + (WebViewGraphicsBased::animatedFlip): + (WebViewGraphicsBased::animatedYFlip): + * QtLauncher/webview.h: + (WebViewGraphicsBased::setYRotation): + (WebViewGraphicsBased::yRotation): + +2010-02-19 Andras Becsi <abecsi@webkit.org> + + Reviewed by Kenneth Rohde Christiansen. + + [Qt] Implement textZoomIn() and textZoomOut() in DRT's EventSender, add results + for passing new tests and unskip the passing ones from the Skipped list. + https://bugs.webkit.org/show_bug.cgi?id=35159 + + * DumpRenderTree/qt/EventSenderQt.cpp: + (EventSender::textZoomIn): + (EventSender::textZoomOut): + * DumpRenderTree/qt/EventSenderQt.h: + +2010-02-19 Laszlo Gombos <laszlo.1.gombos@nokia.com> + + Reviewed by Eric Seidel. + + [Qt] Clean-up the handling of HTML5 persistent data for LayoutTests + https://bugs.webkit.org/show_bug.cgi?id=35004 + + DumpRenderTreeQt.cpp calls QWebSettings::enablePersistentStorage which sets up + and enables all HTML5 persistent data. All the other calls for setting the + persistent path or enabling the persistent feature are redundant. + + * DumpRenderTree/qt/DumpRenderTreeQt.cpp: + (WebCore::WebPage::WebPage): No need to enable AppCache again. + * DumpRenderTree/qt/main.cpp: + (main): No need to setup and enable HTML5 LocalStorage again. + +2010-02-19 Diego Gonzalez <diego.gonzalez@openbossa.org> + + Reviewed by Kenneth Rohde Christiansen. + + Send the context menu event from contextClick() of EventSender + and do not show context menu in DRT. + + LayoutTests: + fast/events/contextmenu-scrolled-page-with-frame.html + + [Qt] DRT: Send context menu event from EventSender + https://bugs.webkit.org/show_bug.cgi?id=35131 + + * DumpRenderTree/qt/DumpRenderTreeQt.cpp: + (WebCore::DumpRenderTree::DumpRenderTree): + * DumpRenderTree/qt/EventSenderQt.cpp: + (EventSender::contextClick): + +2010-02-18 Chris Jerdonek <cjerdonek@webkit.org> + + Reviewed by Shinichiro Hamaji. + + Moved parsing-related code to a separate file. Also increased + the unit test coverage in some affected areas. + + https://bugs.webkit.org/show_bug.cgi?id=34675 + + This revision contains no new functionality. + + * Scripts/check-webkit-style: + - Adjusted to call check_webkit_style_parser(). + + * Scripts/webkitpy/style/checker.py: + - Added check_webkit_style_parser() to pass checker.py + configuration settings to optparser.py. + - Moved _create_usage() and the CommandOptionValues, + DefaultCommandOptionValues, ArgumentPrinter, and + ArgumentParser classes to optparser.py. + + * Scripts/webkitpy/style/checker_unittest.py: + - Moved the ProcessorOptionsTest, ArgumentPrinterTest, and + ArgumentParserTest classes to optparser.py. + - Added the CheckWebKitStyleFunctionTest class to check + the check_webkit_style_configuration() and + check_webkit_style_parser() code paths. + + * Scripts/webkitpy/style/optparser.py: Added. + - From checker.py, added _create_usage() and the + CommandOptionValues, DefaultCommandOptionValues, + ArgumentPrinter, and ArgumentParser classes. + - In the ArgumentParser constructor-- + - Added all_categories as a required parameter. + - Removed the default value from the default_options parameter. + + * Scripts/webkitpy/style/optparser_unittest.py: Added. + - From checker_unittest.py, added the ProcessorOptionsTest, + ArgumentPrinterTest, and ArgumentParserTest classes. + - Added the CreateUsageTest class to test _create_usage(). + + * Scripts/webkitpy/style/unittests.py: + - Added optparser_unittest import. + +2010-02-18 Alexey Proskuryakov <ap@apple.com> + + Reviewed by Dan Bernstein. + + https://bugs.webkit.org/show_bug.cgi?id=35134 + <rdar://problem/7246280> Crash when a plugin calls NPN_SetStatus(0) + + * DumpRenderTree/TestNetscapePlugIn.subproj/PluginObject.cpp: + (testSetStatus): + (pluginInvoke): + Added a setStatus() method. + +2010-02-18 Brady Eidson <beidson@apple.com> + + Reviewed by Sam Weinig. + + Particularly constructed WebFrames can try to access a null HistoryItem + <rdar://problem/7638892> and https://bugs.webkit.org/show_bug.cgi?id=35063 + + Add the specific ability to test this API pattern. + + For now only on Mac, perhaps on the main Windows port later, probably not relevant for other ports. + + * DumpRenderTree/LayoutTestController.cpp: + (apiTestNewWindowDataLoadBaseURLCallback): + (LayoutTestController::staticFunctions): + * DumpRenderTree/LayoutTestController.h: + + * DumpRenderTree/mac/LayoutTestControllerMac.mm: + (-[APITestDelegate initWithCompletionCondition:]): + (-[APITestDelegate webView:didFailLoadWithError:forFrame:]): + (-[APITestDelegate webView:didFailProvisionalLoadWithError:forFrame:]): + (-[APITestDelegate webView:didFinishLoadForFrame:]): + (LayoutTestController::apiTestNewWindowDataLoadBaseURL): Create a WebView, do a loadData: in its + mainFrame, and synchronously wait for main load completion. + + * DumpRenderTree/win/LayoutTestControllerWin.cpp: + (LayoutTestController::apiTestNewWindowDataLoadBaseURL): + * DumpRenderTree/wx/LayoutTestControllerWx.cpp: + (LayoutTestController::apiTestNewWindowDataLoadBaseURL): + * DumpRenderTree/gtk/LayoutTestControllerGtk.cpp: + (LayoutTestController::apiTestNewWindowDataLoadBaseURL): + +2010-02-18 Tor Arne Vestbø <tor.arne.vestbo@nokia.com> + + Reviewed by Eric Seidel. + + Teach resolve-ChangeLogs to act as a merge-driver for Git + + https://bugs.webkit.org/show_bug.cgi?id=28721 + + To enable automatic merging of ChangeLog files, use the following command: + + git config merge.changelog.driver "resolve-ChangeLogs --merge-driver %O %A %B" + + The driver always works in "downstream" merge mode, meaning + it will always put the user's changelog entries on top. + + * Scripts/resolve-ChangeLogs: + +2009-12-05 Gustavo Noronha Silva <gns@gnome.org> + + Reviewed by Eric Seidel. + + Enable running of GTK+ API tests. + + * BuildSlaveSupport/build.webkit.org-config/master.cfg: + * Scripts/run-gtk-tests: Added. + +2010-02-18 Shinichiro Hamaji <hamaji@chromium.org> + + Reviewed by Adam Barth. + + debug-safari doesn't pass --debug option to gdb-safari on MacOSX + https://bugs.webkit.org/show_bug.cgi?id=34411 + + * Scripts/webkitdirs.pm: + +2010-02-18 Eric Seidel <eric@webkit.org> + + Reviewed by Adam Barth. + + run-chromium-webkit-tests --platform=mac-leopard needs to run build-dumprendertree + https://bugs.webkit.org/show_bug.cgi?id=35053 + + * Scripts/webkitpy/layout_tests/port/base.py: Add script_path() function for finding scripts. + * Scripts/webkitpy/layout_tests/port/chromium.py: Remove unused argument. + * Scripts/webkitpy/layout_tests/port/mac.py: + - Make sure that calling webkit-build-directory works even if Scripts/ is not in the user's path. + - Call build-dumprendertree (and make sure it succeeds) before running the tests. + +2010-02-16 Chris Jerdonek <cjerdonek@webkit.org> + + Reviewed by Shinichiro Hamaji. + + Refactored check-webkit-style's ProcessorOptions class into two + classes. This revision contains no new functionality. + + https://bugs.webkit.org/show_bug.cgi?id=34674 + + Divided the ProcessorOptions class into a CommandOptionValues + class (the result of parsing the command-line options) and + a StyleCheckerConfiguration class (which configures the main + StyleChecker). + + * Scripts/check-webkit-style: + - Updated main() to convert the parsed command option values + to a StyleCheckConfiguration instance prior to constructing + a StyleChecker. + + * Scripts/webkitpy/style/checker.py: + - Added check_webkit_style_configuration() to convert a + CommandOptionValues instance into a StyleCheckerConfiguration + instance. + - Renamed the ProcessorOptions class to CommandOptionValues. + - In the CommandOptionValues class-- + - Replaced the filter_configuration attribute with the + simpler filter_rules attribute. + - Removed the max_reports_per_error attribute. + - Moved the is_reportable() method to the new + StyleCheckerConfiguration class. + - Removed the base_filter_rules attribute from the + DefaultCommandOptionValues class. + - In the ArgumentParser class-- + - Added base_filter_rules to the constructor. + - Changed the parse() method to return a CommandOptionValues + instance instead of a ProcessorOptions instance. + - Created a StyleCheckerConfiguration class. + - Added the data attributes max_reports_per_category, + stderr_write, and verbosity. + - Added is_reportable() (moved from the ProcessorOptions + class) and write_style_error() (moved from the + DefaultStyleErrorHandler class). + - In the StyleChecker class-- + - Replaced the ProcessorOptions options attribute with the + StyleCheckerConfiguration _configuration attribute. + - Removed the _stderr_write attribute. + + * Scripts/webkitpy/style/checker_unittest.py: + - Updated the existing unit test classes as necessary. + - Added a StyleCheckerConfigurationTest class. + + * Scripts/webkitpy/style/error_handlers.py: + - Updated the DefaultStyleErrorHandler class to accept a + StyleCheckerConfiguration instance instead of a ProcessorOptions + instance and an stderr_write method. + + * Scripts/webkitpy/style/error_handlers_unittest.py: + - Updated the unit test classes as necessary. + + * Scripts/webkitpy/style/filter.py: + - Addressed the FIXME in the FilterConfiguration class to change + the user_rules attribute to _user_rules (since it is now + accessed only internally). + + * Scripts/webkitpy/style/filter_unittest.py: + - Updated to reflect the change from user_rules to _user_rules. + +2010-02-17 Shinichiro Hamaji <hamaji@chromium.org> + + Reviewed by Eric Seidel. + + Share the DRT values maxViewWidth/Height among ports + https://bugs.webkit.org/show_bug.cgi?id=34474 + + * DumpRenderTree/LayoutTestController.cpp: + (pageNumberForElementByIdCallback): + * DumpRenderTree/LayoutTestController.h: + (LayoutTestController::maxViewWidth): + (LayoutTestController::maxViewHeight): + * DumpRenderTree/gtk/DumpRenderTree.cpp: + (runTest): + * DumpRenderTree/mac/DumpRenderTree.mm: + (createWebViewAndOffscreenWindow): + (sizeWebViewForCurrentTest): + * DumpRenderTree/win/DumpRenderTree.cpp: + (dump): + (createWebViewAndOffscreenWindow): + +2010-02-17 Shinichiro Hamaji <hamaji@chromium.org> + + Reviewed by Eric Seidel. + + [Win] Implement test functions for printing + https://bugs.webkit.org/show_bug.cgi?id=34570 + + * DumpRenderTree/win/LayoutTestControllerWin.cpp: + (LayoutTestController::pageNumberForElementById): + (LayoutTestController::numberOfPages): + +2010-02-17 Fumitoshi Ukai <ukai@chromium.org> + + Reviewed by Eric Seidel. + + websocket/tests/cookies/httponly-cookie.pl fails every time under run-chromium-webkit-tests + https://bugs.webkit.org/show_bug.cgi?id=35001 + + * Scripts/webkitpy/layout_tests/port/websocket_server.py: add -x flag to run pywebsocket. + +2010-02-17 Shinichiro Hamaji <hamaji@chromium.org> + + Reviewed by Eric Seidel. + + check-webkit-style: Misses variables that contain underscores. + https://bugs.webkit.org/show_bug.cgi?id=33724 + + - Check identifiers whose types are unsigned. + - Check bitfields properly. + + * Scripts/webkitpy/style/processors/cpp.py: + * Scripts/webkitpy/style/processors/cpp_unittest.py: + +2010-02-17 Shinichiro Hamaji <hamaji@chromium.org> + + Reviewed by Eric Seidel. + + check-webkit-style should report the number of files checked + https://bugs.webkit.org/show_bug.cgi?id=34971 + + * Scripts/check-webkit-style: + * Scripts/webkitpy/style/checker.py: + * Scripts/webkitpy/style/checker_unittest.py: + +2010-02-17 Diego Gonzalez <diego.gonzalez@openbossa.org> + + Reviewed by Ariya Hidayat. + + Make possible Qt DRT to get total number of pages to be printed + + LayoutTests: + printing/numberOfPages.html + + [Qt] DRT: Get total number of pages to be printed + https://bugs.webkit.org/show_bug.cgi?id=34955 + + * DumpRenderTree/qt/LayoutTestControllerQt.cpp: + (LayoutTestController::numberOfPages): + * DumpRenderTree/qt/LayoutTestControllerQt.h: + +2010-02-17 Xan Lopez <xlopez@igalia.com> + + Reviewed by Gustavo Noronha. + + Update to use new property name. + + * DumpRenderTree/gtk/DumpRenderTree.cpp: + (resetDefaultsToConsistentValues): + +2010-02-17 Julien Chaffraix <jchaffraix@webkit.org> + + Reviewed by Ariya Hidayat. + + Remove some warnings seen when building Qt + https://bugs.webkit.org/show_bug.cgi?id=35017 + + Using a machine without the needed tools to build WebKit leads to + several errors and warnings. + + * Scripts/webkitdirs.pm: Refactored the code testing the command's + presence into a commandExists routine. While doing so removed, stderr + output as it usually does not give anything more than our message. Also + added a Qt check for qmake that was missing. + +2010-02-17 Xan Lopez <xlopez@igalia.com> + + Rubber-stamped by Gustavo Noronha. + + Disable Java by default in DRT. + + * DumpRenderTree/gtk/DumpRenderTree.cpp: + (resetDefaultsToConsistentValues): + +2010-02-15 Chris Jerdonek <cjerdonek@webkit.org> + + Reviewed by Shinichiro Hamaji. + + Some minor check-webkit-style code clean-ups. This revision + contains no new functionality. + + https://bugs.webkit.org/show_bug.cgi?id=34932 + + * Scripts/check-webkit-style: + - Replaced the call to webkit_argument_defaults() with a + default parameter in the ArgumentParser constructor. + + * Scripts/webkitpy/style/checker.py: + - Removed the WEBKIT prefix from the default global variables. + - Prefixed several of the global variables with an underscore + to reflect that they are used internally. + - Renamed _DEFAULT_FILTER_RULES to _BASE_FILTER_RULES. + - Addressed a FIXME by changing the _PATH_RULES_SPECIFIER + configuration from list-tuple pairs to list-list pairs. + - Renamed style_categories() to _all_categories(). + - Renamed webkit_argument_defaults() to _check_webkit_style_defaults(). + - Renamed the ArgumentDefaults class to DefaultCommandOptionValues. + - In the ArgumentParser class-- + - Renamed the doc_print attribute to stderr_write. + - Other minor updates. + + * Scripts/webkitpy/style/checker_unittest.py: + - Updated the import statements and unit test classes as necessary. + - Added assertions to test _PATH_RULES_SPECIFIER more fully. + + * Scripts/webkitpy/style/error_handlers_unittest.py: + - Updated the unit test classes as necessary. + - Changed StyleErrorHandlerTestBase to store a list of error + messages rather than just the last one. + + * Scripts/webkitpy/style/filter.py: + - Altered FilterConfiguration._path_rules_from_path() + to convert the path_rules list to a tuple. + + * Scripts/webkitpy/style/filter_unittest.py: + - Updated the unit tests to reflect the change from tuples to + lists in the _PATH_RULES_SPECIFIER configuration variable. + +2010-02-16 Mark Rowe <mrowe@apple.com> + + Let's not check garbage in to common build scripts and hose the world now eh guys? + + * Scripts/webkitdirs.pm: + +2010-02-16 Eric Seidel <eric@webkit.org> + + Reviewed by Adam Barth. + + re-factor Skipped list parsing code into multiple functions and unit test it + https://bugs.webkit.org/show_bug.cgi?id=34986 + + * Scripts/test-webkitpy: Add new unit test. + * Scripts/webkitpy/layout_tests/__init__.py: Copied from WebKitTools/QueueStatusServer/filters/__init__.py. + * Scripts/webkitpy/layout_tests/port/mac.py: Split parsing function into multiple functions for testing. + * Scripts/webkitpy/layout_tests/port/mac_unittest.py: Added. + +2010-02-16 Xan Lopez <xlopez@igalia.com> + + Reviewed by Gustavo Noronha. + + Enable 'auto-resize-window' in our DRT. + + * DumpRenderTree/gtk/DumpRenderTree.cpp: + (resetDefaultsToConsistentValues): + +2010-02-15 Martin Robinson <mrobinson@webkit.org> + + Reviewed by Darin Adler. + + check-webkit-style should not complain about NULL sentinel in calls to g_strconcat and g_strjoin + https://bugs.webkit.org/show_bug.cgi?id=34834 + + * Scripts/webkitpy/style/processors/cpp.py: + * Scripts/webkitpy/style/processors/cpp_unittest.py: + +2010-02-12 Alexey Proskuryakov <ap@apple.com> + + Reviewed by Kevin Decker. + + <rdar://problem/7130641> Browser objects identity is not preserved by Safari + + * DumpRenderTree/TestNetscapePlugIn.subproj/PluginObject.cpp: + (pluginInvoke): Added methods for checking object identity (via refcount). + +2010-02-15 Robert Hogan <robert@roberthogan.net> + + Reviewed by Simon Hausmann. + + [Qt] DRT: Support evaluateInWebInspector(), setTimelineProfilingEnabled(). + + Support LayoutTestController.evaluateInWebInspector(), setTimelineProfilingEnabled() in Qt DRT. + + https://bugs.webkit.org/show_bug.cgi?id=33096 + + This allows the following tests to pass: + + inspector/console-format-collections.html + inspector/styles-iframe.html + inspector/syntax-highlight-css.html + inspector/syntax-highlight-javascript.html + inspector/timeline-enum-stability.html + inspector/timeline-layout.html + inspector/timeline-mark-timeline.html + inspector/timeline-paint.html + inspector/timeline-parse-html.html + inspector/timeline-recalculate-styles.html + inspector/timeline-script-tag-1.html + inspector/timeline-script-tag-2.html + inspector/timeline-trivial.html + inspector/cookie-resource-match.html + inspector/elements-img-tooltip.html + inspector/elements-panel-selection-on-refresh.html + inspector/inspected-objects-not-overriden.html + inspector/timeline-event-dispatch.html + inspector/timeline-network-resource.html + inspector/elements-panel-rewrite-href.html + inspector/console-dir.html + inspector/console-dirxml.html + inspector/console-format.html + inspector/console-tests.html + inspector/elements-panel-structure.html + inspector/evaluate-in-frontend.html + inspector/console-clear.html + + * DumpRenderTree/qt/DumpRenderTreeQt.cpp: + (WebCore::DumpRenderTree::resetToConsistentStateBeforeTesting): + (WebCore::isWebInspectorTest): + (WebCore::DumpRenderTree::open): + * DumpRenderTree/qt/DumpRenderTreeQt.h: + (WebCore::DumpRenderTree::display): + * DumpRenderTree/qt/LayoutTestControllerQt.cpp: + (LayoutTestController::closeWebInspector): + (LayoutTestController::showWebInspector): + (LayoutTestController::evaluateInWebInspector): + (LayoutTestController::setTimelineProfilingEnabled): + (LayoutTestController::display): + * DumpRenderTree/qt/LayoutTestControllerQt.h: + +2010-02-14 Dirk Pranke <dpranke@chromium.org> + + Reviewed by Eric Seidel. + + Update rebaseline-chromium-webkit-tests to work with the new code + structure (port objects instead of path_utils and platform_utils). + + Added a path_to_test_expectations_file() to the Port interface. + + Fixed a bug in the chromium_* platform implementations where the + 'target' option was assumed to be set. + + * Scripts/rebaseline-chromium-webkit-tests: + * Scripts/webkitpy/layout_tests/layout_package/test_expectations.py: + * Scripts/webkitpy/layout_tests/port/base.py: + * Scripts/webkitpy/layout_tests/port/chromium.py: + * Scripts/webkitpy/layout_tests/port/chromium_linux.py: + * Scripts/webkitpy/layout_tests/port/chromium_mac.py: + * Scripts/webkitpy/layout_tests/port/chromium_win.py: + * Scripts/webkitpy/layout_tests/port/test.py: + * Scripts/webkitpy/layout_tests/rebaseline_chromium_webkit_tests.py: + +2010-02-14 Eric Seidel <eric@webkit.org> + + Reviewed by Darin Adler. + + webkit-build-directory misuses terms + https://bugs.webkit.org/show_bug.cgi?id=34822 + + * Scripts/webkit-build-directory: + - Add --top-level and --configuration options and make using one of them required. + * Scripts/webkitpy/layout_tests/port/mac.py: + - Use --top-level instead of --base. + +2010-02-14 Chang Shu <Chang.Shu@nokia.com> + + Reviewed by Laszlo Gombos. + + [Qt] Enable appcache feature. + https://bugs.webkit.org/show_bug.cgi?id=34713 + + Re-land r54543 without the change in DumpRenderTree/qt/main.cpp. + Persistent storage for AppCache is already initialized in + DumpRenderTreeQt.cpp. + + * DumpRenderTree/qt/DumpRenderTreeQt.cpp: + (WebCore::WebPage::WebPage): + +2010-02-12 Chang Shu <Chang.Shu@nokia.com> + + Not Reviewed. + + Change case of my email address as a work-around for the following bug. + https://bugs.webkit.org/show_bug.cgi?id=34717 + + * Scripts/webkitpy/committers.py: + +2010-02-12 Darin Adler <darin@apple.com> + + Ignore compiled Python in more of webkitpy. + + * Scripts/webkitpy/style/processors: Added property svn:ignore. + 2010-02-12 Diego Gonzalez <diego.gonzalez@openbossa.org> Reviewed by Kenneth Rohde Christiansen. diff --git a/WebKitTools/DumpRenderTree/LayoutTestController.cpp b/WebKitTools/DumpRenderTree/LayoutTestController.cpp index c2393c3..f528b31 100644 --- a/WebKitTools/DumpRenderTree/LayoutTestController.cpp +++ b/WebKitTools/DumpRenderTree/LayoutTestController.cpp @@ -467,10 +467,8 @@ static JSValueRef notifyDoneCallback(JSContextRef context, JSObjectRef function, static bool parsePageParameters(JSContextRef context, int argumentCount, const JSValueRef* arguments, JSValueRef* exception, float& pageWidthInPixels, float& pageHeightInPixels) { - // FIXME: These values should sync with maxViewWidth/Height in - // DumpRenderTree.mm. Factor these values out to somewhere. - pageWidthInPixels = 800; - pageHeightInPixels = 600; + pageWidthInPixels = LayoutTestController::maxViewWidth; + pageHeightInPixels = LayoutTestController::maxViewHeight; switch (argumentCount) { case 2: pageWidthInPixels = static_cast<float>(JSValueToNumber(context, arguments[0], exception)); @@ -940,6 +938,18 @@ static JSValueRef setAllowUniversalAccessFromFileURLsCallback(JSContextRef conte return JSValueMakeUndefined(context); } +static JSValueRef setAllowFileAccessFromFileURLsCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + // Has mac & windows implementation + if (argumentCount < 1) + return JSValueMakeUndefined(context); + + LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject)); + controller->setAllowFileAccessFromFileURLs(JSValueToBoolean(context, arguments[0])); + + return JSValueMakeUndefined(context); +} + static JSValueRef setTabKeyCyclesThroughElementsCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) { // Has mac & windows implementation @@ -1252,6 +1262,22 @@ static JSValueRef addUserStyleSheetCallback(JSContextRef context, JSObjectRef, J return JSValueMakeUndefined(context); } +static JSValueRef apiTestNewWindowDataLoadBaseURLCallback(JSContextRef context, JSObjectRef, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +{ + if (argumentCount != 2) + return JSValueMakeUndefined(context); + + JSRetainPtr<JSStringRef> utf8Data(Adopt, JSValueToStringCopy(context, arguments[0], exception)); + ASSERT(!*exception); + + JSRetainPtr<JSStringRef> baseURL(Adopt, JSValueToStringCopy(context, arguments[1], exception)); + ASSERT(!*exception); + + LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject)); + controller->apiTestNewWindowDataLoadBaseURL(utf8Data.get(), baseURL.get()); + return JSValueMakeUndefined(context); +} + // Static Values static JSValueRef getGlobalFlagCallback(JSContextRef context, JSObjectRef thisObject, JSStringRef propertyName, JSValueRef* exception) @@ -1328,6 +1354,7 @@ JSStaticFunction* LayoutTestController::staticFunctions() { "addDisallowedURL", addDisallowedURLCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, { "addUserScript", addUserScriptCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, { "addUserStyleSheet", addUserStyleSheetCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "apiTestNewWindowDataLoadBaseURL", apiTestNewWindowDataLoadBaseURLCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, { "clearAllDatabases", clearAllDatabasesCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, { "clearBackForwardList", clearBackForwardListCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, { "clearPersistentUserStyleSheet", clearPersistentUserStyleSheetCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, @@ -1380,6 +1407,7 @@ JSStaticFunction* LayoutTestController::staticFunctions() { "repaintSweepHorizontally", repaintSweepHorizontallyCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, { "setAcceptsEditing", setAcceptsEditingCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, { "setAllowUniversalAccessFromFileURLs", setAllowUniversalAccessFromFileURLsCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, + { "setAllowFileAccessFromFileURLs", setAllowFileAccessFromFileURLsCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, { "setAlwaysAcceptCookies", setAlwaysAcceptCookiesCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, { "setAppCacheMaximumSize", setAppCacheMaximumSizeCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, { "setAuthenticationPassword", setAuthenticationPasswordCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete }, @@ -1492,3 +1520,6 @@ void LayoutTestController::setPOSIXLocale(JSStringRef locale) JSStringGetUTF8CString(locale, localeBuf, sizeof(localeBuf)); setlocale(LC_ALL, localeBuf); } + +const unsigned LayoutTestController::maxViewWidth = 800; +const unsigned LayoutTestController::maxViewHeight = 600; diff --git a/WebKitTools/DumpRenderTree/LayoutTestController.h b/WebKitTools/DumpRenderTree/LayoutTestController.h index 5f9df50..3add32a 100644 --- a/WebKitTools/DumpRenderTree/LayoutTestController.h +++ b/WebKitTools/DumpRenderTree/LayoutTestController.h @@ -69,6 +69,7 @@ public: void removeAllVisitedLinks(); void setAcceptsEditing(bool acceptsEditing); void setAllowUniversalAccessFromFileURLs(bool); + void setAllowFileAccessFromFileURLs(bool); void setAppCacheMaximumSize(unsigned long long quota); void setAuthorAndUserStylesEnabled(bool); void setCacheModel(int); @@ -232,6 +233,13 @@ public: void evaluateScriptInIsolatedWorld(unsigned worldId, JSObjectRef globalObject, JSStringRef script); void setPOSIXLocale(JSStringRef locale); + + // The following API test functions should probably be moved to platform-specific + // unit tests outside of DRT once they exist. + void apiTestNewWindowDataLoadBaseURL(JSStringRef utf8Data, JSStringRef baseURL); + + static const unsigned maxViewWidth; + static const unsigned maxViewHeight; private: bool m_dumpAsPDF; diff --git a/WebKitTools/DumpRenderTree/TestNetscapePlugIn.subproj/PluginObject.cpp b/WebKitTools/DumpRenderTree/TestNetscapePlugIn.subproj/PluginObject.cpp index e69da73..8e278f5 100644 --- a/WebKitTools/DumpRenderTree/TestNetscapePlugIn.subproj/PluginObject.cpp +++ b/WebKitTools/DumpRenderTree/TestNetscapePlugIn.subproj/PluginObject.cpp @@ -176,6 +176,11 @@ enum { ID_TEST_RELOAD_PLUGINS_AND_PAGES, ID_TEST_GET_BROWSER_PROPERTY, ID_TEST_SET_BROWSER_PROPERTY, + ID_REMEMBER, + ID_GET_REMEMBERED_OBJECT, + ID_GET_AND_FORGET_REMEMBERED_OBJECT, + ID_REF_COUNT, + ID_SET_STATUS, NUM_METHOD_IDENTIFIERS }; @@ -205,7 +210,12 @@ static const NPUTF8 *pluginMethodIdentifierNames[NUM_METHOD_IDENTIFIERS] = { "reloadPluginsNoPages", "reloadPluginsAndPages", "testGetBrowserProperty", - "testSetBrowserProperty" + "testSetBrowserProperty", + "remember", + "getRememberedObject", + "getAndForgetRememberedObject", + "refCount", + "setStatus" }; static NPUTF8* createCStringFromNPVariant(const NPVariant* variant) @@ -747,6 +757,22 @@ bool testWindowOpen(NPP npp) return false; } +static bool testSetStatus(PluginObject* obj, const NPVariant* args, uint32_t argCount, NPVariant* result) +{ + char* message = 0; + if (argCount && NPVARIANT_IS_STRING(args[0])) { + NPString statusString = NPVARIANT_TO_STRING(args[0]); + message = toCString(statusString); + } + + browser->status(obj->npp, message); + + free(message); + return true; +} + +static NPObject* rememberedObject; + static bool pluginInvoke(NPObject* header, NPIdentifier name, const NPVariant* args, uint32_t argCount, NPVariant* result) { PluginObject* plugin = reinterpret_cast<PluginObject*>(header); @@ -807,7 +833,29 @@ static bool pluginInvoke(NPObject* header, NPIdentifier name, const NPVariant* a } else if (name == pluginMethodIdentifiers[ID_TEST_SET_BROWSER_PROPERTY]) { browser->setproperty(plugin->npp, NPVARIANT_TO_OBJECT(args[0]), stringVariantToIdentifier(args[1]), &args[2]); return true; - } + } else if (name == pluginMethodIdentifiers[ID_REMEMBER]) { + if (rememberedObject) + browser->releaseobject(rememberedObject); + rememberedObject = NPVARIANT_TO_OBJECT(args[0]); + browser->retainobject(rememberedObject); + VOID_TO_NPVARIANT(*result); + return true; + } else if (name == pluginMethodIdentifiers[ID_GET_REMEMBERED_OBJECT]) { + assert(rememberedObject); + browser->retainobject(rememberedObject); + OBJECT_TO_NPVARIANT(rememberedObject, *result); + return true; + } else if (name == pluginMethodIdentifiers[ID_GET_AND_FORGET_REMEMBERED_OBJECT]) { + assert(rememberedObject); + OBJECT_TO_NPVARIANT(rememberedObject, *result); + rememberedObject = 0; + return true; + } else if (name == pluginMethodIdentifiers[ID_REF_COUNT]) { + uint32_t refCount = NPVARIANT_TO_OBJECT(args[0])->referenceCount; + INT32_TO_NPVARIANT(refCount, *result); + return true; + } else if (name == pluginMethodIdentifiers[ID_SET_STATUS]) + return testSetStatus(plugin, args, argCount, result); return false; } diff --git a/WebKitTools/DumpRenderTree/gtk/DumpRenderTree.cpp b/WebKitTools/DumpRenderTree/gtk/DumpRenderTree.cpp index 39430cf..a2fc79b 100644 --- a/WebKitTools/DumpRenderTree/gtk/DumpRenderTree.cpp +++ b/WebKitTools/DumpRenderTree/gtk/DumpRenderTree.cpp @@ -94,8 +94,6 @@ GSList* webViewList = 0; // current b/f item at the end of the previous test static WebKitWebHistoryItem* prevTestBFItem = NULL; -const unsigned maxViewHeight = 600; -const unsigned maxViewWidth = 800; const unsigned historyItemIndent = 8; static gchar* autocorrectURL(const gchar* url) @@ -335,6 +333,8 @@ static void resetDefaultsToConsistentValues() "minimum-font-size", 1, "enable-caret-browsing", FALSE, "enable-page-cache", FALSE, + "auto-resize-window", TRUE, + "enable-java-applet", FALSE, NULL); webkit_web_frame_clear_main_frame_name(mainFrame); @@ -477,8 +477,8 @@ static void runTest(const string& testPathOrURL) bool isSVGW3CTest = (gLayoutTestController->testPathOrURL().find("svg/W3C-SVG-1.1") != string::npos); GtkAllocation size; size.x = size.y = 0; - size.width = isSVGW3CTest ? 480 : maxViewWidth; - size.height = isSVGW3CTest ? 360 : maxViewHeight; + size.width = isSVGW3CTest ? 480 : LayoutTestController::maxViewWidth; + size.height = isSVGW3CTest ? 360 : LayoutTestController::maxViewHeight; gtk_window_resize(GTK_WINDOW(window), size.width, size.height); gtk_widget_size_allocate(container, &size); diff --git a/WebKitTools/DumpRenderTree/gtk/LayoutTestControllerGtk.cpp b/WebKitTools/DumpRenderTree/gtk/LayoutTestControllerGtk.cpp index 422e2c2..668b852 100644 --- a/WebKitTools/DumpRenderTree/gtk/LayoutTestControllerGtk.cpp +++ b/WebKitTools/DumpRenderTree/gtk/LayoutTestControllerGtk.cpp @@ -348,6 +348,15 @@ void LayoutTestController::setAllowUniversalAccessFromFileURLs(bool flag) g_object_set(G_OBJECT(settings), "enable-universal-access-from-file-uris", flag, NULL); } +void LayoutTestController::setAllowFileAccessFromFileURLs(bool flag) +{ + WebKitWebView* view = webkit_web_frame_get_web_view(mainFrame); + ASSERT(view); + + WebKitWebSettings* settings = webkit_web_view_get_settings(view); + g_object_set(G_OBJECT(settings), "enable-file-access-from-file-uris", flag, NULL); +} + void LayoutTestController::setAuthorAndUserStylesEnabled(bool flag) { // FIXME: implement @@ -586,3 +595,8 @@ void LayoutTestController::removeAllVisitedLinks() { // FIXME: Implement this. } + +void LayoutTestController::apiTestNewWindowDataLoadBaseURL(JSStringRef utf8Data, JSStringRef baseURL) +{ + +} diff --git a/WebKitTools/DumpRenderTree/mac/DumpRenderTree.mm b/WebKitTools/DumpRenderTree/mac/DumpRenderTree.mm index 7a4429b..c7ddf21 100644 --- a/WebKitTools/DumpRenderTree/mac/DumpRenderTree.mm +++ b/WebKitTools/DumpRenderTree/mac/DumpRenderTree.mm @@ -134,9 +134,6 @@ static RetainPtr<CFStringRef> persistentUserStyleSheetLocation; static WebHistoryItem *prevTestBFItem = nil; // current b/f item at the end of the previous test -const unsigned maxViewHeight = 600; -const unsigned maxViewWidth = 800; - #if __OBJC2__ static void swizzleAllMethods(Class imposter, Class original) { @@ -279,7 +276,7 @@ static void activateFonts() WebView *createWebViewAndOffscreenWindow() { - NSRect rect = NSMakeRect(0, 0, maxViewWidth, maxViewHeight); + NSRect rect = NSMakeRect(0, 0, LayoutTestController::maxViewWidth, LayoutTestController::maxViewHeight); WebView *webView = [[WebView alloc] initWithFrame:rect frameName:nil groupName:@"org.webkit.DumpRenderTree"]; [webView setUIDelegate:uiDelegate]; @@ -396,6 +393,7 @@ static void resetDefaultsToConsistentValues() WebPreferences *preferences = [WebPreferences standardPreferences]; [preferences setAllowUniversalAccessFromFileURLs:YES]; + [preferences setAllowFileAccessFromFileURLs:YES]; [preferences setStandardFontFamily:@"Times"]; [preferences setFixedFontFamily:@"Courier"]; [preferences setSerifFontFamily:@"Times"]; @@ -1020,7 +1018,7 @@ static void sizeWebViewForCurrentTest() if (isSVGW3CTest) [[mainFrame webView] setFrameSize:NSMakeSize(480, 360)]; else - [[mainFrame webView] setFrameSize:NSMakeSize(maxViewWidth, maxViewHeight)]; + [[mainFrame webView] setFrameSize:NSMakeSize(LayoutTestController::maxViewWidth, LayoutTestController::maxViewHeight)]; } static const char *methodNameStringForFailedTest() diff --git a/WebKitTools/DumpRenderTree/mac/LayoutTestControllerMac.mm b/WebKitTools/DumpRenderTree/mac/LayoutTestControllerMac.mm index b726e72..66ba5f0 100644 --- a/WebKitTools/DumpRenderTree/mac/LayoutTestControllerMac.mm +++ b/WebKitTools/DumpRenderTree/mac/LayoutTestControllerMac.mm @@ -334,6 +334,11 @@ void LayoutTestController::setAllowUniversalAccessFromFileURLs(bool enabled) [[[mainFrame webView] preferences] setAllowUniversalAccessFromFileURLs:enabled]; } +void LayoutTestController::setAllowFileAccessFromFileURLs(bool enabled) +{ + [[[mainFrame webView] preferences] setAllowFileAccessFromFileURLs:enabled]; +} + void LayoutTestController::setPopupBlockingEnabled(bool popupBlockingEnabled) { [[[mainFrame webView] preferences] setJavaScriptCanOpenWindowsAutomatically:!popupBlockingEnabled]; @@ -617,3 +622,67 @@ void LayoutTestController::evaluateScriptInIsolatedWorld(unsigned worldID, JSObj [mainFrame _stringByEvaluatingJavaScriptFromString:scriptNS withGlobalObject:globalObject inScriptWorld:world]; } + +@interface APITestDelegate : NSObject +{ + bool* m_condition; +} +@end + +@implementation APITestDelegate + +- (id)initWithCompletionCondition:(bool*)condition +{ + [super init]; + ASSERT(condition); + m_condition = condition; + *m_condition = false; + return self; +} + +- (void)webView:(WebView *)sender didFailLoadWithError:(NSError *)error forFrame:(WebFrame *)frame +{ + printf("API Test load failed\n"); + *m_condition = true; +} + +- (void)webView:(WebView *)sender didFailProvisionalLoadWithError:(NSError *)error forFrame:(WebFrame *)frame +{ + printf("API Test load failed provisional\n"); + *m_condition = true; +} + +- (void)webView:(WebView *)sender didFinishLoadForFrame:(WebFrame *)frame +{ + printf("API Test load succeeded\n"); + *m_condition = true; +} + +@end + +void LayoutTestController::apiTestNewWindowDataLoadBaseURL(JSStringRef utf8Data, JSStringRef baseURL) +{ + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + + RetainPtr<CFStringRef> utf8DataCF(AdoptCF, JSStringCopyCFString(kCFAllocatorDefault, utf8Data)); + RetainPtr<CFStringRef> baseURLCF(AdoptCF, JSStringCopyCFString(kCFAllocatorDefault, baseURL)); + + WebView *webView = [[WebView alloc] initWithFrame:NSZeroRect frameName:@"" groupName:@""]; + + bool done = false; + APITestDelegate *delegate = [[APITestDelegate alloc] initWithCompletionCondition:&done]; + [webView setFrameLoadDelegate:delegate]; + + [[webView mainFrame] loadData:[(NSString *)utf8DataCF.get() dataUsingEncoding:NSUTF8StringEncoding] MIMEType:@"text/html" textEncodingName:@"utf-8" baseURL:[NSURL URLWithString:(NSString *)baseURLCF.get()]]; + + while (!done) { + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantPast]]; + [pool release]; + } + + [webView close]; + [webView release]; + [delegate release]; + [pool release]; +} diff --git a/WebKitTools/DumpRenderTree/qt/DumpRenderTreeQt.cpp b/WebKitTools/DumpRenderTree/qt/DumpRenderTreeQt.cpp index c16a786..43f1318 100644 --- a/WebKitTools/DumpRenderTree/qt/DumpRenderTreeQt.cpp +++ b/WebKitTools/DumpRenderTree/qt/DumpRenderTreeQt.cpp @@ -135,7 +135,6 @@ WebPage::WebPage(QObject* parent, DumpRenderTree* drt) globalSettings->setAttribute(QWebSettings::LocalContentCanAccessRemoteUrls, true); globalSettings->setAttribute(QWebSettings::JavascriptEnabled, true); globalSettings->setAttribute(QWebSettings::PrivateBrowsingEnabled, false); - globalSettings->setAttribute(QWebSettings::OfflineWebApplicationCacheEnabled, false); connect(this, SIGNAL(geometryChangeRequested(const QRect &)), this, SLOT(setViewGeometry(const QRect & ))); @@ -324,6 +323,7 @@ DumpRenderTree::DumpRenderTree() m_mainView->resize(QSize(maxViewWidth, maxViewHeight)); m_page = new WebPage(m_mainView, this); m_mainView->setPage(m_page); + m_mainView->setContextMenuPolicy(Qt::NoContextMenu); // create our controllers. This has to be done before connectFrame, // as it exports there to the JavaScript DOM window. @@ -412,10 +412,23 @@ void DumpRenderTree::resetToConsistentStateBeforeTesting() setlocale(LC_ALL, ""); } +static bool isWebInspectorTest(const QUrl& url) +{ + if (url.path().contains("inspector/")) + return true; + return false; +} + void DumpRenderTree::open(const QUrl& url) { resetToConsistentStateBeforeTesting(); + if (isWebInspectorTest(m_page->mainFrame()->url())) + layoutTestController()->closeWebInspector(); + + if (isWebInspectorTest(url)) + layoutTestController()->showWebInspector(); + // W3C SVG tests expect to be 480x360 bool isW3CTest = url.toString().contains("svg/W3C-SVG-1.1"); int width = isW3CTest ? 480 : maxViewWidth; diff --git a/WebKitTools/DumpRenderTree/qt/DumpRenderTreeQt.h b/WebKitTools/DumpRenderTree/qt/DumpRenderTreeQt.h index 00d7ae4..8d80f87 100644 --- a/WebKitTools/DumpRenderTree/qt/DumpRenderTreeQt.h +++ b/WebKitTools/DumpRenderTree/qt/DumpRenderTreeQt.h @@ -158,6 +158,7 @@ public: WebPage(QObject* parent, DumpRenderTree*); virtual ~WebPage(); QWebInspector* webInspector(); + void closeWebInspector(); QWebPage *createWindow(QWebPage::WebWindowType); diff --git a/WebKitTools/DumpRenderTree/qt/EventSenderQt.cpp b/WebKitTools/DumpRenderTree/qt/EventSenderQt.cpp index 73a9934..1ef2d3f 100644 --- a/WebKitTools/DumpRenderTree/qt/EventSenderQt.cpp +++ b/WebKitTools/DumpRenderTree/qt/EventSenderQt.cpp @@ -274,6 +274,8 @@ void EventSender::contextClick() QApplication::sendEvent(m_page, &event); QMouseEvent event2(QEvent::MouseButtonRelease, m_mousePos, Qt::RightButton, Qt::RightButton, Qt::NoModifier); QApplication::sendEvent(m_page, &event2); + QContextMenuEvent event3(QContextMenuEvent::Mouse, m_mousePos); + QApplication::sendEvent(m_page->view(), &event3); } void EventSender::scheduleAsynchronousClick() @@ -397,18 +399,28 @@ void EventSender::sendTouchEvent(QEvent::Type type) void EventSender::zoomPageIn() { - QWebFrame* frame = m_page->mainFrame(); - if (frame) + if (QWebFrame* frame = m_page->mainFrame()) frame->setZoomFactor(frame->zoomFactor() * ZOOM_STEP); } void EventSender::zoomPageOut() { - QWebFrame* frame = m_page->mainFrame(); - if (frame) + if (QWebFrame* frame = m_page->mainFrame()) frame->setZoomFactor(frame->zoomFactor() / ZOOM_STEP); } +void EventSender::textZoomIn() +{ + if (QWebFrame* frame = m_page->mainFrame()) + frame->setTextSizeMultiplier(frame->textSizeMultiplier() * ZOOM_STEP); +} + +void EventSender::textZoomOut() +{ + if (QWebFrame* frame = m_page->mainFrame()) + frame->setTextSizeMultiplier(frame->textSizeMultiplier() / ZOOM_STEP); +} + QWebFrame* EventSender::frameUnderMouse() const { QWebFrame* frame = m_page->mainFrame(); diff --git a/WebKitTools/DumpRenderTree/qt/EventSenderQt.h b/WebKitTools/DumpRenderTree/qt/EventSenderQt.h index f6cfc7c..38bca89 100644 --- a/WebKitTools/DumpRenderTree/qt/EventSenderQt.h +++ b/WebKitTools/DumpRenderTree/qt/EventSenderQt.h @@ -68,6 +68,8 @@ public slots: void touchEnd(); void zoomPageIn(); void zoomPageOut(); + void textZoomIn(); + void textZoomOut(); void clearTouchPoints(); void releaseTouchPoint(int index); diff --git a/WebKitTools/DumpRenderTree/qt/LayoutTestControllerQt.cpp b/WebKitTools/DumpRenderTree/qt/LayoutTestControllerQt.cpp index 51c1181..a26bc3d 100644 --- a/WebKitTools/DumpRenderTree/qt/LayoutTestControllerQt.cpp +++ b/WebKitTools/DumpRenderTree/qt/LayoutTestControllerQt.cpp @@ -41,6 +41,7 @@ extern void qt_dump_frame_loader(bool b); extern void qt_dump_resource_load_callbacks(bool b); extern void qt_drt_setFrameSetFlatteningEnabled(QWebPage*, bool); extern void qt_drt_setJavaScriptProfilingEnabled(QWebFrame*, bool enabled); +extern void qt_drt_setTimelineProfilingEnabled(QWebPage*, bool enabled); extern bool qt_drt_pauseAnimation(QWebFrame*, const QString& name, double time, const QString& elementId); extern bool qt_drt_pauseTransitionOfProperty(QWebFrame*, const QString& name, double time, const QString& elementId); extern bool qt_drt_pauseSVGAnimation(QWebFrame*, const QString& animationId, double time, const QString& elementId); @@ -51,6 +52,10 @@ extern void qt_drt_whiteListAccessFromOrigin(const QString& sourceOrigin, const extern QString qt_drt_counterValueForElementById(QWebFrame* qFrame, const QString& id); extern int qt_drt_workerThreadCount(); extern int qt_drt_pageNumberForElementById(QWebFrame* qFrame, const QString& id, float width, float height); +extern int qt_drt_numberOfPages(QWebFrame* qFrame, float width, float height); +extern void qt_drt_webinspector_executeScript(QWebPage* page, long callId, const QString& script); +extern void qt_drt_webinspector_show(QWebPage *page); +extern void qt_drt_webinspector_close(QWebPage *page); LayoutTestController::LayoutTestController(WebCore::DumpRenderTree* drt) : QObject() @@ -285,15 +290,22 @@ QString LayoutTestController::decodeHostName(const QString& host) return decoded; } + +void LayoutTestController::closeWebInspector() +{ + qt_drt_webinspector_close(m_drt->webPage()); + m_drt->webPage()->settings()->setAttribute(QWebSettings::DeveloperExtrasEnabled, false); +} + void LayoutTestController::showWebInspector() { m_drt->webPage()->settings()->setAttribute(QWebSettings::DeveloperExtrasEnabled, true); - m_drt->webPage()->webInspector()->show(); + qt_drt_webinspector_show(m_drt->webPage()); } -void LayoutTestController::hideWebInspector() +void LayoutTestController::evaluateInWebInspector(long callId, const QString& script) { - m_drt->webPage()->webInspector()->hide(); + qt_drt_webinspector_executeScript(m_drt->webPage(), callId, script); } void LayoutTestController::setFrameSetFlatteningEnabled(bool enabled) @@ -306,12 +318,22 @@ void LayoutTestController::setAllowUniversalAccessFromFileURLs(bool enabled) m_drt->webPage()->settings()->setAttribute(QWebSettings::LocalContentCanAccessRemoteUrls, enabled); } +void LayoutTestController::setAllowFileAccessFromFileURLs(bool enabled) +{ + m_drt->webPage()->settings()->setAttribute(QWebSettings::LocalContentCanAccessFileUrls, enabled); +} + void LayoutTestController::setJavaScriptProfilingEnabled(bool enable) { m_topLoadingFrame->page()->settings()->setAttribute(QWebSettings::DeveloperExtrasEnabled, true); qt_drt_setJavaScriptProfilingEnabled(m_topLoadingFrame, enable); } +void LayoutTestController::setTimelineProfilingEnabled(bool enable) +{ + qt_drt_setTimelineProfilingEnabled(m_drt->webPage(), enable); +} + void LayoutTestController::setFixedContentsSize(int width, int height) { m_topLoadingFrame->page()->setPreferredContentsSize(QSize(width, height)); @@ -473,3 +495,8 @@ int LayoutTestController::pageNumberForElementById(const QString& id, float widt return qt_drt_pageNumberForElementById(m_drt->webPage()->mainFrame(), id, width, height); } + +int LayoutTestController::numberOfPages(float width, float height) +{ + return qt_drt_numberOfPages(m_drt->webPage()->mainFrame(), width, height); +} diff --git a/WebKitTools/DumpRenderTree/qt/LayoutTestControllerQt.h b/WebKitTools/DumpRenderTree/qt/LayoutTestControllerQt.h index 64cbcc9..d73794e 100644 --- a/WebKitTools/DumpRenderTree/qt/LayoutTestControllerQt.h +++ b/WebKitTools/DumpRenderTree/qt/LayoutTestControllerQt.h @@ -115,11 +115,14 @@ public slots: QString decodeHostName(const QString& host); void dumpSelectionRect() const {} void showWebInspector(); - void hideWebInspector(); + void closeWebInspector(); + void evaluateInWebInspector(long callId, const QString& script); void setFrameSetFlatteningEnabled(bool enable); void setAllowUniversalAccessFromFileURLs(bool enable); + void setAllowFileAccessFromFileURLs(bool enable); void setJavaScriptProfilingEnabled(bool enable); + void setTimelineProfilingEnabled(bool enable); void setFixedContentsSize(int width, int height); void setPrivateBrowsingEnabled(bool enable); void setPopupBlockingEnabled(bool enable); @@ -150,6 +153,7 @@ public slots: void setDomainRelaxationForbiddenForURLScheme(bool forbidden, const QString& scheme); int workerThreadCount(); int pageNumberForElementById(const QString& id, float width = 0, float height = 0); + int numberOfPages(float width, float height); private slots: void processWork(); diff --git a/WebKitTools/DumpRenderTree/qt/main.cpp b/WebKitTools/DumpRenderTree/qt/main.cpp index efcda57..7d72982 100644 --- a/WebKitTools/DumpRenderTree/qt/main.cpp +++ b/WebKitTools/DumpRenderTree/qt/main.cpp @@ -37,9 +37,7 @@ #include <qdir.h> #include <qdebug.h> #include <qfont.h> -#include <qwebsettings.h> #include <qwebdatabase.h> -#include <qdesktopservices.h> #include <qtimer.h> #include <qwindowsstyle.h> @@ -161,8 +159,6 @@ int main(int argc, char* argv[]) if (args.contains(QLatin1String("--pixel-tests"))) dumper.setDumpPixels(true); - QString dbDir = QDesktopServices::storageLocation(QDesktopServices::DataLocation) + QDir::separator() + "qtwebkitdrt"; - QWebSettings::setOfflineStoragePath(dbDir); QWebDatabase::removeAllDatabases(); if (args.contains(QLatin1String("-"))) { diff --git a/WebKitTools/DumpRenderTree/win/DumpRenderTree.cpp b/WebKitTools/DumpRenderTree/win/DumpRenderTree.cpp index 261b9e6..ddfca95 100644 --- a/WebKitTools/DumpRenderTree/win/DumpRenderTree.cpp +++ b/WebKitTools/DumpRenderTree/win/DumpRenderTree.cpp @@ -107,9 +107,6 @@ LayoutTestController* gLayoutTestController = 0; UINT_PTR waitToDumpWatchdog = 0; -const unsigned maxViewWidth = 800; -const unsigned maxViewHeight = 600; - void setPersistentUserStyleSheetLocation(CFStringRef url) { persistentUserStyleSheetLocation = url; @@ -667,8 +664,8 @@ void dump() width = 480; height = 360; } else { - width = maxViewWidth; - height = maxViewHeight; + width = LayoutTestController::maxViewWidth; + height = LayoutTestController::maxViewHeight; } ::SetWindowPos(webViewWindow, 0, 0, 0, width, height, SWP_NOMOVE); @@ -787,6 +784,7 @@ static void resetDefaultsToConsistentValues(IWebPreferences* preferences) COMPtr<IWebPreferencesPrivate> prefsPrivate(Query, preferences); if (prefsPrivate) { prefsPrivate->setAllowUniversalAccessFromFileURLs(TRUE); + prefsPrivate->setAllowFileAccessFromFileURLs(TRUE); prefsPrivate->setAuthorAndUserStylesEnabled(TRUE); prefsPrivate->setDeveloperExtrasEnabled(FALSE); prefsPrivate->setExperimentalNotificationsEnabled(TRUE); @@ -1097,6 +1095,8 @@ WindowToWebViewMap& windowToWebViewMap() IWebView* createWebViewAndOffscreenWindow(HWND* webViewWindow) { + unsigned maxViewWidth = LayoutTestController::maxViewWidth; + unsigned maxViewHeight = LayoutTestController::maxViewHeight; HWND hostWindow = CreateWindowEx(WS_EX_TOOLWINDOW, kDumpRenderTreeClassName, TEXT("DumpRenderTree"), WS_POPUP, -maxViewWidth, -maxViewHeight, maxViewWidth, maxViewHeight, 0, 0, GetModuleHandle(0), 0); diff --git a/WebKitTools/DumpRenderTree/win/LayoutTestControllerWin.cpp b/WebKitTools/DumpRenderTree/win/LayoutTestControllerWin.cpp index 34fd2e6..9f84488 100644 --- a/WebKitTools/DumpRenderTree/win/LayoutTestControllerWin.cpp +++ b/WebKitTools/DumpRenderTree/win/LayoutTestControllerWin.cpp @@ -406,6 +406,23 @@ void LayoutTestController::setAllowUniversalAccessFromFileURLs(bool enabled) prefsPrivate->setAllowUniversalAccessFromFileURLs(enabled); } +void LayoutTestController::setAllowFileAccessFromFileURLs(bool enabled) +{ + COMPtr<IWebView> webView; + if (FAILED(frame->webView(&webView))) + return; + + COMPtr<IWebPreferences> preferences; + if (FAILED(webView->preferences(&preferences))) + return; + + COMPtr<IWebPreferencesPrivate> prefsPrivate(Query, preferences); + if (!prefsPrivate) + return; + + prefsPrivate->setAllowFileAccessFromFileURLs(enabled); +} + void LayoutTestController::setPopupBlockingEnabled(bool enabled) { COMPtr<IWebView> webView; @@ -1121,14 +1138,34 @@ JSRetainPtr<JSStringRef> LayoutTestController::counterValueForElementById(JSStri return counterValueJS; } -int LayoutTestController::pageNumberForElementById(JSStringRef, float, float) +int LayoutTestController::pageNumberForElementById(JSStringRef id, float pageWidthInPixels, float pageHeightInPixels) { - // FIXME: implement - return -1; + COMPtr<IWebFramePrivate> framePrivate(Query, frame); + if (!framePrivate) + return 0; + + wstring idWstring = jsStringRefToWString(id); + BSTR idBSTR = SysAllocStringLen((OLECHAR*)idWstring.c_str(), idWstring.length()); + int pageNumber = -1; + if (FAILED(framePrivate->pageNumberForElementById(idBSTR, pageWidthInPixels, pageHeightInPixels, &pageNumber))) + pageNumber = -1; + SysFreeString(idBSTR); + return pageNumber; } -int LayoutTestController::numberOfPages(float, float) +int LayoutTestController::numberOfPages(float pageWidthInPixels, float pageHeightInPixels) { - // FIXME: implement - return -1; + COMPtr<IWebFramePrivate> framePrivate(Query, frame); + if (!framePrivate) + return 0; + + int pageNumber = -1; + if (FAILED(framePrivate->numberOfPages(pageWidthInPixels, pageHeightInPixels, &pageNumber))) + pageNumber = -1; + return pageNumber; +} + +void LayoutTestController::apiTestNewWindowDataLoadBaseURL(JSStringRef utf8Data, JSStringRef baseURL) +{ + } diff --git a/WebKitTools/DumpRenderTree/wx/LayoutTestControllerWx.cpp b/WebKitTools/DumpRenderTree/wx/LayoutTestControllerWx.cpp index 3bc84cd..ce1bda5 100644 --- a/WebKitTools/DumpRenderTree/wx/LayoutTestControllerWx.cpp +++ b/WebKitTools/DumpRenderTree/wx/LayoutTestControllerWx.cpp @@ -180,6 +180,11 @@ void LayoutTestController::setAllowUniversalAccessFromFileURLs(bool enabled) // FIXME: implement } +void LayoutTestController::setAllowFileAccessFromFileURLs(bool enabled) +{ + // FIXME: implement +} + void LayoutTestController::setAuthorAndUserStylesEnabled(bool flag) { // FIXME: implement @@ -375,4 +380,9 @@ int LayoutTestController::numberOfPages(float, float) { // FIXME: implement return -1; -}
\ No newline at end of file +} + +void LayoutTestController::apiTestNewWindowDataLoadBaseURL(JSStringRef utf8Data, JSStringRef baseURL) +{ + +} diff --git a/WebKitTools/QtLauncher/main.cpp b/WebKitTools/QtLauncher/main.cpp index c725c2f..1203ce7 100644 --- a/WebKitTools/QtLauncher/main.cpp +++ b/WebKitTools/QtLauncher/main.cpp @@ -133,6 +133,8 @@ private: WebInspector* inspector; QAction* formatMenuAction; + QAction* flipAnimated; + QAction* flipYAnimated; #if QT_VERSION >= QT_VERSION_CHECK(4, 6, 0) QList<QTouchEvent::TouchPoint> touchPoints; @@ -461,6 +463,13 @@ void LauncherWindow::initializeView(bool useGraphicsView) if (gShowFrameRate) view->enableFrameRateMeasurement(); page()->settings()->setAttribute(QWebSettings::AcceleratedCompositingEnabled, gUseCompositing); + + if (flipAnimated) + connect(flipAnimated, SIGNAL(triggered()), view, SLOT(animatedFlip())); + + if (flipYAnimated) + connect(flipYAnimated, SIGNAL(triggered()), view, SLOT(animatedYFlip())); + m_view = view; } @@ -540,13 +549,26 @@ void LauncherWindow::setupUI() touchMockAction->setShortcut(QKeySequence(Qt::CTRL | Qt::ALT | Qt::Key_T)); #endif - QAction* toggleAcceleratedCompositing = toolsMenu->addAction("Toggle Accelerated Compositing", this, SLOT(toggleAcceleratedCompositing(bool))); + QMenu* graphicsViewMenu = toolsMenu->addMenu("QGraphicsView"); + QAction* toggleGraphicsView = graphicsViewMenu->addAction("Toggle use of QGraphicsView", this, SLOT(initializeView(bool))); + toggleGraphicsView->setCheckable(true); + toggleGraphicsView->setChecked(false); + + QAction* toggleAcceleratedCompositing = graphicsViewMenu->addAction("Toggle Accelerated Compositing", this, SLOT(toggleAcceleratedCompositing(bool))); toggleAcceleratedCompositing->setCheckable(true); toggleAcceleratedCompositing->setChecked(false); + toggleAcceleratedCompositing->setEnabled(false); + toggleAcceleratedCompositing->connect(toggleGraphicsView, SIGNAL(toggled(bool)), SLOT(setEnabled(bool))); - QAction* toggleGraphicsView = toolsMenu->addAction("Toggle use of QGraphicsView", this, SLOT(initializeView(bool))); - toggleGraphicsView->setCheckable(true); - toggleGraphicsView->setChecked(false); + graphicsViewMenu->addSeparator(); + + flipAnimated = graphicsViewMenu->addAction("Animated Flip"); + flipAnimated->connect(toggleGraphicsView, SIGNAL(toggled(bool)), SLOT(setEnabled(bool))); + flipAnimated->setEnabled(false); + + flipYAnimated = graphicsViewMenu->addAction("Animated Y-Flip"); + flipYAnimated->connect(toggleGraphicsView, SIGNAL(toggled(bool)), SLOT(setEnabled(bool))); + flipYAnimated->setEnabled(false); } QWebPage* WebPage::createWindow(QWebPage::WebWindowType type) diff --git a/WebKitTools/QtLauncher/webview.cpp b/WebKitTools/QtLauncher/webview.cpp index 443fc3e..311d79b 100644 --- a/WebKitTools/QtLauncher/webview.cpp +++ b/WebKitTools/QtLauncher/webview.cpp @@ -48,6 +48,29 @@ 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 } void WebViewGraphicsBased::resizeEvent(QResizeEvent* event) @@ -83,6 +106,30 @@ void WebViewGraphicsBased::updateFrameRate() m_numPaintsSinceLastMeasure = 0; } +void WebViewGraphicsBased::animatedFlip() +{ +#if QT_VERSION >= QT_VERSION_CHECK(4, 6, 0) + QSizeF center = m_item->boundingRect().size() / 2; + QPointF centerPoint = QPointF(center.width(), center.height()); + m_item->setTransformOriginPoint(centerPoint); + + QPropertyAnimation* animation = new QPropertyAnimation(m_item, "rotation", this); + animation->setDuration(1000); + + int rotation = int(m_item->rotation()); + + animation->setStartValue(rotation); + animation->setEndValue(rotation + 180 - (rotation % 180)); + + animation->start(QAbstractAnimation::DeleteWhenStopped); +#endif +} + +void WebViewGraphicsBased::animatedYFlip() +{ + emit yFlipRequest(); +} + void WebViewGraphicsBased::paintEvent(QPaintEvent* event) { QGraphicsView::paintEvent(event); diff --git a/WebKitTools/QtLauncher/webview.h b/WebKitTools/QtLauncher/webview.h index 83bd801..297d975 100644 --- a/WebKitTools/QtLauncher/webview.h +++ b/WebKitTools/QtLauncher/webview.h @@ -66,6 +66,7 @@ protected: class WebViewGraphicsBased : public QGraphicsView { Q_OBJECT + Q_PROPERTY(qreal yRotation READ yRotation WRITE setYRotation) public: WebViewGraphicsBased(QWidget* parent); @@ -76,8 +77,29 @@ public: void enableFrameRateMeasurement(); virtual void paintEvent(QPaintEvent* event); + void setYRotation(qreal angle) + { +#if QT_VERSION >= QT_VERSION_CHECK(4, 6, 0) + QRectF r = m_item->boundingRect(); + m_item->setTransform(QTransform() + .translate(r.width() / 2, r.height() / 2) + .rotate(angle, Qt::YAxis) + .translate(-r.width() / 2, -r.height() / 2)); +#endif + m_yRotation = angle; + } + qreal yRotation() const + { + return m_yRotation; + } + public slots: void updateFrameRate(); + void animatedFlip(); + void animatedYFlip(); + +signals: + void yFlipRequest(); private: GraphicsWebView* m_item; @@ -86,6 +108,7 @@ private: QTime m_startTime; QTime m_lastConsultTime; bool m_measureFps; + qreal m_yRotation; }; #endif diff --git a/WebKitTools/Scripts/check-webkit-style b/WebKitTools/Scripts/check-webkit-style index 501264b..ea2e943 100755 --- a/WebKitTools/Scripts/check-webkit-style +++ b/WebKitTools/Scripts/check-webkit-style @@ -57,13 +57,11 @@ def main(): codecs.getreader('utf8'), codecs.getwriter('utf8'), 'replace') - - defaults = checker.webkit_argument_defaults() - - parser = checker.ArgumentParser(defaults) + parser = checker.check_webkit_style_parser() (files, options) = parser.parse(sys.argv[1:]) - style_checker = checker.StyleChecker(options) + configuration = checker.check_webkit_style_configuration(options) + style_checker = checker.StyleChecker(configuration) if files: for filename in files: @@ -87,8 +85,11 @@ def main(): style_checker.check_patch(patch) error_count = style_checker.error_count - sys.stderr.write('Total errors found: %d\n' % error_count) - sys.exit(error_count > 0) + file_count = style_checker.file_count + sys.stderr.write('Total errors found: %d in %d files\n' + % (error_count, file_count)) + # We fail when style errors are found or there are no checked files. + sys.exit(error_count > 0 or file_count == 0) if __name__ == "__main__": diff --git a/WebKitTools/Scripts/rebaseline-chromium-webkit-tests b/WebKitTools/Scripts/rebaseline-chromium-webkit-tests index aea0edc..302995c 100755 --- a/WebKitTools/Scripts/rebaseline-chromium-webkit-tests +++ b/WebKitTools/Scripts/rebaseline-chromium-webkit-tests @@ -33,6 +33,7 @@ import sys sys.path.append(os.path.join(os.path.dirname(os.path.abspath(sys.argv[0])), "webkitpy", "layout_tests")) +sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(sys.argv[0])))) import rebaseline_chromium_webkit_tests diff --git a/WebKitTools/Scripts/resolve-ChangeLogs b/WebKitTools/Scripts/resolve-ChangeLogs index 1a2d2af..3238350 100755 --- a/WebKitTools/Scripts/resolve-ChangeLogs +++ b/WebKitTools/Scripts/resolve-ChangeLogs @@ -34,6 +34,7 @@ use FindBin; use lib $FindBin::Bin; use File::Basename; +use File::Copy; use File::Path; use File::Spec; use Getopt::Long; @@ -64,28 +65,30 @@ my $GIT = "git"; my $fixMerged; my $gitRebaseContinue = 0; +my $mergeDriver = 0; my $printWarnings = 1; my $showHelp; my $getOptionsResult = GetOptions( - 'c|continue!' => \$gitRebaseContinue, - 'f|fix-merged:s' => \&parseFixMerged, - 'h|help' => \$showHelp, - 'w|warnings!' => \$printWarnings, + 'c|continue!' => \$gitRebaseContinue, + 'f|fix-merged:s' => \&parseFixMerged, + 'm|merge-driver!' => \$mergeDriver, + 'h|help' => \$showHelp, + 'w|warnings!' => \$printWarnings, ); my $relativePath = isInGitFilterBranch() ? '.' : chdirReturningRelativePath(determineVCSRoot()); my @changeLogFiles = removeChangeLogArguments($relativePath); -if (!defined $fixMerged && scalar(@changeLogFiles) == 0) { +if (!defined $fixMerged && !$mergeDriver && scalar(@changeLogFiles) == 0) { @changeLogFiles = findUnmergedChangeLogs(); } -if (scalar(@ARGV) > 0) { +if (!$mergeDriver && scalar(@ARGV) > 0) { print STDERR "ERROR: Files listed on command-line that are not ChangeLogs.\n"; undef $getOptionsResult; -} elsif (!defined $fixMerged && scalar(@changeLogFiles) == 0) { +} elsif (!defined $fixMerged && !$mergeDriver && scalar(@changeLogFiles) == 0) { print STDERR "ERROR: No ChangeLog files listed on command-line or found unmerged.\n"; undef $getOptionsResult; } elsif ($gitRebaseContinue && !$isGit) { @@ -94,6 +97,12 @@ if (scalar(@ARGV) > 0) { } elsif (defined $fixMerged && !$isGit) { print STDERR "ERROR: --fix-merged may only be used with a git repository\n"; undef $getOptionsResult; +} elsif ($mergeDriver && !$isGit) { + print STDERR "ERROR: --merge-driver may only be used with a git repository\n"; + undef $getOptionsResult; +} elsif ($mergeDriver && scalar(@ARGV) < 3) { + print STDERR "ERROR: --merge-driver expects %O %A %B as arguments\n"; + undef $getOptionsResult; } sub usageAndExit() @@ -104,6 +113,7 @@ Usage: @{[ basename($0) ]} [options] [path/to/ChangeLog] [path/to/another/Change entries (default: --no-continue) -f|--fix-merged [revision-range] fix git-merged ChangeLog entries; if a revision-range is specified, run git filter-branch on the range + -m|--merge-driver %O %A %B act as a git merge-driver on files %O %A %B -h|--help show this help message -w|--[no-]warnings show or suppress warnings (default: show warnings) __END__ @@ -118,6 +128,14 @@ if (defined $fixMerged && length($fixMerged) > 0) { my $commitRange = $fixMerged; $commitRange = $commitRange . "..HEAD" if index($commitRange, "..") < 0; fixMergedChangeLogs($commitRange, @changeLogFiles); +} elsif ($mergeDriver) { + my ($base, $theirs, $ours) = @ARGV; + if (mergeChanges($ours, $base, $theirs)) { + unlink($ours); + copy($theirs, $ours) or die $!; + } else { + exit 1; + } } elsif (@changeLogFiles) { for my $file (@changeLogFiles) { if (defined $fixMerged) { diff --git a/WebKitTools/Scripts/run-gtk-tests b/WebKitTools/Scripts/run-gtk-tests new file mode 100644 index 0000000..9a57319 --- /dev/null +++ b/WebKitTools/Scripts/run-gtk-tests @@ -0,0 +1,35 @@ +#!/usr/bin/perl +# +# Copyright (C) 2009 Gustavo Noronha Silva <gns@gnome.org> +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Library General Public +# License as published by the Free Software Foundation; either +# version 2 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Library General Public License for more details. +# +# You should have received a copy of the GNU Library General Public License +# along with this library; see the file COPYING.LIB. If not, write to +# the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, +# Boston, MA 02110-1301, USA. + +use strict; +use warnings; + +use FindBin; +use lib $FindBin::Bin; +use webkitdirs; + +# This initializes the correct configuration (Release/Debug) +setConfiguration(); + +my $productDir = productDir(); +my @unitTests = glob $productDir . "/Programs/unittests/*"; +if ($#unitTests < 1) { + die "ERROR: tests not found in $productDir.\n"; +} +system "gtester -k @unitTests" diff --git a/WebKitTools/Scripts/test-webkitpy b/WebKitTools/Scripts/test-webkitpy index cfd3434..8617330 100755 --- a/WebKitTools/Scripts/test-webkitpy +++ b/WebKitTools/Scripts/test-webkitpy @@ -44,6 +44,7 @@ from webkitpy.credentials_unittest import * from webkitpy.diff_parser_unittest import * from webkitpy.executive_unittest import * from webkitpy.grammar_unittest import * +from webkitpy.layout_tests.port.mac_unittest import * from webkitpy.multicommandtool_unittest import * from webkitpy.networktransaction_unittest import * from webkitpy.patchcollection_unittest import * diff --git a/WebKitTools/Scripts/webkit-build-directory b/WebKitTools/Scripts/webkit-build-directory index a85c587..bf7d66d 100755 --- a/WebKitTools/Scripts/webkit-build-directory +++ b/WebKitTools/Scripts/webkit-build-directory @@ -34,31 +34,35 @@ use Getopt::Long; use lib $FindBin::Bin; use webkitdirs; -my $showBaseProductDirectory = 0; +my $showConfigurationDirectory = 0; my $showHelp = 0; +my $showTopLevelDirectory = 0; + my $programName = basename($0); my $usage = <<EOF; Usage: $programName [options] - --base Show the root build directory instead of one corresponding to the current target (e.g. Debug, Release) - --debug Show build directory for the Debug target - -h|--help Show this help message - --release Show build directory for the Release target + --configuration Show the build directory for a specific configuration (e.g. Debug, Release. Defaults to the active configuration set by set-webkit-configuration) + -h|--help Show this help message + --top-level Show the top-level build directory + +Either --configuration or --top-level is required. EOF setConfiguration(); # Figure out from the command line if we're --debug or --release or the default. my $getOptionsResult = GetOptions( - 'base' => \$showBaseProductDirectory, + 'configuration' => \$showConfigurationDirectory, + 'top-level' => \$showTopLevelDirectory, 'help|h' => \$showHelp, ); -if (!$getOptionsResult || $showHelp) { +if (!$getOptionsResult || $showHelp || (!$showConfigurationDirectory && !$showTopLevelDirectory)) { print STDERR $usage; exit 1; } -if ($showBaseProductDirectory) { +if ($showTopLevelDirectory) { print baseProductDir() . "\n"; } else { print productDir() . "\n"; diff --git a/WebKitTools/Scripts/webkitdirs.pm b/WebKitTools/Scripts/webkitdirs.pm index a788b3d..7985790 100644 --- a/WebKitTools/Scripts/webkitdirs.pm +++ b/WebKitTools/Scripts/webkitdirs.pm @@ -614,9 +614,17 @@ sub qtFeatureDefaults() return %qtFeatureDefaults; } +sub commandExists($) +{ + my $command = shift; + my $devnull = File::Spec->devnull(); + return `$command --version 2> $devnull`; +} + sub determineQtFeatureDefaults() { return if %qtFeatureDefaults; + die "ERROR: qmake missing but required to build WebKit.\n" if not commandExists("qmake"); my $originalCwd = getcwd(); chdir File::Spec->catfile(sourceDir(), "WebCore"); my $defaults = `qmake CONFIG+=compute_defaults 2>&1`; @@ -891,10 +899,9 @@ sub checkRequiredSystemConfig my @cmds = qw(flex bison gperf); my @missing = (); foreach my $cmd (@cmds) { - if (not `$cmd --version`) { - push @missing, $cmd; - } + push @missing, $cmd if not commandExists($cmd); } + if (@missing) { my $list = join ", ", @missing; die "ERROR: $list missing but required to build WebKit.\n"; @@ -1162,7 +1169,7 @@ sub qtMakeCommand($) #print "default spec: " . $mkspec . "\n"; #print "compiler found: " . $compiler . "\n"; - if ($compiler eq "cl") { + if ($compiler && $compiler eq "cl") { return "nmake"; } @@ -1454,7 +1461,7 @@ sub runSafari my ($debugger) = @_; if (isAppleMacWebKit()) { - return system "$FindBin::Bin/gdb-safari", @ARGV if $debugger; + return system "$FindBin::Bin/gdb-safari", argumentsForConfiguration() if $debugger; my $productDir = productDir(); print "Starting Safari with DYLD_FRAMEWORK_PATH set to point to built WebKit in $productDir.\n"; diff --git a/WebKitTools/Scripts/webkitpy/committers.py b/WebKitTools/Scripts/webkitpy/committers.py index 7af0987..6413243 100644 --- a/WebKitTools/Scripts/webkitpy/committers.py +++ b/WebKitTools/Scripts/webkitpy/committers.py @@ -82,7 +82,7 @@ committers_unable_to_review = [ Committer("Brian Weinstein", "bweinstein@apple.com"), Committer("Cameron McCormack", "cam@webkit.org"), Committer("Carol Szabo", "carol.szabo@nokia.com"), - Committer("Chang Shu", "chang.shu@nokia.com"), + Committer("Chang Shu", "Chang.Shu@nokia.com"), Committer("Chris Fleizach", "cfleizach@apple.com"), Committer("Chris Jerdonek", "cjerdonek@webkit.org"), Committer("Chris Marrin", "cmarrin@apple.com"), diff --git a/WebKitTools/Scripts/webkitpy/layout_tests/__init__.py b/WebKitTools/Scripts/webkitpy/layout_tests/__init__.py new file mode 100644 index 0000000..ef65bee --- /dev/null +++ b/WebKitTools/Scripts/webkitpy/layout_tests/__init__.py @@ -0,0 +1 @@ +# Required for Python to search this directory for module files 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 a3650ed..01add62 100644 --- a/WebKitTools/Scripts/webkitpy/layout_tests/layout_package/test_expectations.py +++ b/WebKitTools/Scripts/webkitpy/layout_tests/layout_package/test_expectations.py @@ -35,7 +35,6 @@ import logging import os import re import sys -import time import simplejson @@ -133,10 +132,9 @@ class TestExpectations: def has_modifier(self, test, modifier): return self._expected_failures.has_modifier(test, modifier) - def remove_platform_from_file(self, tests, platform, backup=False): - return self._expected_failures.remove_platform_from_file(tests, - platform, - backup) + def remove_platform_from_expectations(self, tests, platform): + return self._expected_failures.remove_platform_from_expectations( + tests, platform) def strip_comments(line): @@ -373,8 +371,9 @@ class TestExpectationsFile: def contains(self, test): return test in self._test_to_expectations - def remove_platform_from_file(self, tests, platform, backup=False): - """Remove the platform option from test expectations file. + def remove_platform_from_expectations(self, tests, platform): + """Returns a copy of the expectations with the tests matching the + platform remove. If a test is in the test list and has an option that matches the given platform, remove the matching platform and save the updated test back @@ -384,24 +383,13 @@ class TestExpectationsFile: Args: tests: list of tests that need to update.. platform: which platform option to remove. - backup: if true, the original test expectations file is saved as - [self.TEST_LIST].orig.YYYYMMDDHHMMSS Returns: - no + the updated string. """ - # FIXME - remove_platform_from file worked by writing a new - # test_expectations.txt file over the old one. Now that we're just - # parsing strings, we need to change this to return the new - # expectations string. - raise NotImplementedException('remove_platform_from_file') - - new_file = self._path + '.new' - logging.debug('Original file: "%s"', self._path) - logging.debug('New file: "%s"', new_file) f_orig = self._get_iterable_expectations() - f_new = open(new_file, 'w') + f_new = [] tests_removed = 0 tests_updated = 0 @@ -413,7 +401,7 @@ class TestExpectationsFile: if action == NO_CHANGE: # Save the original line back to the file logging.debug('No change to test: %s', line) - f_new.write(line) + f_new.append(line) elif action == REMOVE_TEST: tests_removed += 1 logging.info('Test removed: %s', line) @@ -421,7 +409,7 @@ class TestExpectationsFile: parts = line.split(':') new_options = parts[0].replace(platform.upper() + ' ', '', 1) new_line = ('%s:%s' % (new_options, parts[1])) - f_new.write(new_line) + f_new.append(new_line) tests_updated += 1 logging.info('Test updated: ') logging.info(' old: %s', line) @@ -440,7 +428,7 @@ class TestExpectationsFile: if not p in (platform.upper(), 'WIN-VISTA', 'WIN-7'): new_options += p + ' ' new_line = ('%s:%s' % (new_options, parts[1])) - f_new.write(new_line) + f_new.append(new_line) tests_updated += 1 logging.info('Test updated: ') logging.info(' old: %s', line) @@ -452,23 +440,7 @@ class TestExpectationsFile: logging.info('Total tests removed: %d', tests_removed) logging.info('Total tests updated: %d', tests_updated) - f_orig.close() - f_new.close() - - if backup: - date_suffix = time.strftime('%Y%m%d%H%M%S', - time.localtime(time.time())) - backup_file = ('%s.orig.%s' % (self._path, date_suffix)) - if os.path.exists(backup_file): - os.remove(backup_file) - logging.info('Saving original file to "%s"', backup_file) - os.rename(self._path, backup_file) - else: - os.remove(self._path) - - logging.debug('Saving new file to "%s"', self._path) - os.rename(new_file, self._path) - return True + return "".join(f_new) def parse_expectations_line(self, line, lineno): """Parses a line from test_expectations.txt and returns a tuple diff --git a/WebKitTools/Scripts/webkitpy/layout_tests/port/base.py b/WebKitTools/Scripts/webkitpy/layout_tests/port/base.py index ce06b44..2b25e29 100644 --- a/WebKitTools/Scripts/webkitpy/layout_tests/port/base.py +++ b/WebKitTools/Scripts/webkitpy/layout_tests/port/base.py @@ -83,18 +83,20 @@ class Port(object): interface so that it can be overriden for testing purposes.""" return actual_text != expected_text - def diff_image(self, actual_filename, expected_filename, diff_filename): + def diff_image(self, actual_filename, expected_filename, + diff_filename=None): """Compare two image files and produce a delta image file. Return 1 if the two files are different, 0 if they are the same. Also produce a delta image of the two images and write that into - |diff_filename|. + |diff_filename| if it is not None. While this is a generic routine, we include it in the Port interface so that it can be overriden for testing purposes.""" executable = self._path_to_image_diff() - cmd = [executable, '--diff', actual_filename, expected_filename, - diff_filename] + cmd = [executable, '--diff', actual_filename, expected_filename] + if diff_filename: + cmd.append(diff_filename) result = 1 try: result = subprocess.call(cmd) @@ -267,6 +269,7 @@ class Port(object): used by run-chromium-webkit-tests.""" raise NotImplementedError('Port.num_cores') + # FIXME: This could be replaced by functions in webkitpy.scm. def path_from_webkit_base(self, *comps): """Returns the full path to path made by joining the top of the WebKit source tree and the list of path components in |*comps|.""" @@ -275,6 +278,17 @@ class Port(object): self._webkit_base_dir = abspath[0:abspath.find('WebKitTools')] return os.path.join(self._webkit_base_dir, *comps) + # FIXME: Callers should eventually move to scm.script_path. + def script_path(self, script_name): + return self.path_from_webkit_base("WebKitTools", "Scripts", script_name) + + def path_to_test_expectations_file(self): + """Update the test expectations to the passed-in string. + + This is used by the rebaselining tool. Raises NotImplementedError + if the port does not use expectations files.""" + raise NotImplementedError('Port.path_to_test_expectations_file') + def remove_directory(self, *path): """Recursively removes a directory, even if it's marked read-only. diff --git a/WebKitTools/Scripts/webkitpy/layout_tests/port/chromium.py b/WebKitTools/Scripts/webkitpy/layout_tests/port/chromium.py index 70a8dea..1123376 100644 --- a/WebKitTools/Scripts/webkitpy/layout_tests/port/chromium.py +++ b/WebKitTools/Scripts/webkitpy/layout_tests/port/chromium.py @@ -88,6 +88,10 @@ class ChromiumPort(base.Port): self._chromium_base_dir = abspath[0:abspath.find('third_party')] return os.path.join(self._chromium_base_dir, *comps) + def path_to_test_expectations_file(self): + return self.path_from_chromium_base('webkit', 'tools', 'layout_tests', + 'test_expectations.txt') + def results_directory(self): return self.path_from_chromium_base('webkit', self._options.target, self._options.results_directory) @@ -128,13 +132,12 @@ class ChromiumPort(base.Port): def test_base_platform_names(self): return ('linux', 'mac', 'win') - def test_expectations(self, options=None): + def test_expectations(self): """Returns the test expectations for this port. Basically this string should contain the equivalent of a test_expectations file. See test_expectations.py for more details.""" - expectations_file = self.path_from_chromium_base('webkit', 'tools', - 'layout_tests', 'test_expectations.txt') + expectations_file = self.path_to_test_expectations_file() return file(expectations_file, "r").read() def test_platform_names(self): @@ -154,7 +157,6 @@ class ChromiumPort(base.Port): return self.path_from_chromium_base('webkit', 'data', 'layout_tests', 'platform', platform, 'LayoutTests') - class ChromiumDriver(base.Driver): """Abstract interface for the DumpRenderTree interface.""" diff --git a/WebKitTools/Scripts/webkitpy/layout_tests/port/chromium_linux.py b/WebKitTools/Scripts/webkitpy/layout_tests/port/chromium_linux.py index 8fd5343..b817251 100644 --- a/WebKitTools/Scripts/webkitpy/layout_tests/port/chromium_linux.py +++ b/WebKitTools/Scripts/webkitpy/layout_tests/port/chromium_linux.py @@ -43,6 +43,8 @@ class ChromiumLinuxPort(chromium.ChromiumPort): def __init__(self, port_name=None, options=None): if port_name is None: port_name = 'chromium-linux' + if options and not hasattr(options, 'target'): + options.target = 'Release' chromium.ChromiumPort.__init__(self, port_name, options) def baseline_search_path(self): diff --git a/WebKitTools/Scripts/webkitpy/layout_tests/port/chromium_mac.py b/WebKitTools/Scripts/webkitpy/layout_tests/port/chromium_mac.py index 7e7b4ca..bcffcf8 100644 --- a/WebKitTools/Scripts/webkitpy/layout_tests/port/chromium_mac.py +++ b/WebKitTools/Scripts/webkitpy/layout_tests/port/chromium_mac.py @@ -43,6 +43,8 @@ class ChromiumMacPort(chromium.ChromiumPort): def __init__(self, port_name=None, options=None): if port_name is None: port_name = 'chromium-mac' + if options and not hasattr(options, 'target'): + options.target = 'Release' chromium.ChromiumPort.__init__(self, port_name, options) def baseline_search_path(self): diff --git a/WebKitTools/Scripts/webkitpy/layout_tests/port/chromium_win.py b/WebKitTools/Scripts/webkitpy/layout_tests/port/chromium_win.py index 352916c..5eb0ba1 100644 --- a/WebKitTools/Scripts/webkitpy/layout_tests/port/chromium_win.py +++ b/WebKitTools/Scripts/webkitpy/layout_tests/port/chromium_win.py @@ -44,6 +44,8 @@ class ChromiumWinPort(chromium.ChromiumPort): def __init__(self, port_name=None, options=None): if port_name is None: port_name = 'chromium-win' + self.version() + if options and not hasattr(options, 'target'): + options.target = 'Release' chromium.ChromiumPort.__init__(self, port_name, options) def baseline_search_path(self): diff --git a/WebKitTools/Scripts/webkitpy/layout_tests/port/mac.py b/WebKitTools/Scripts/webkitpy/layout_tests/port/mac.py index 4b73cec..d355f62 100644 --- a/WebKitTools/Scripts/webkitpy/layout_tests/port/mac.py +++ b/WebKitTools/Scripts/webkitpy/layout_tests/port/mac.py @@ -67,8 +67,16 @@ class MacPort(base.Port): return dirs def check_sys_deps(self): - # FIXME: This should run build-dumprendertree. - # This should also validate that all of the tool paths are valid. + if executive.run_command([self.script_path("build-dumprendertree")], return_exit_code=True) != 0: + return False + + driver_path = self._path_to_driver() + if not os.path.exists(driver_path): + logging.error("DumpRenderTree was not found at %s" % driver_path) + return False + + # This should also validate that the ImageDiff path is valid (once this script knows how to use ImageDiff). + # https://bugs.webkit.org/show_bug.cgi?id=34826 return True def num_cores(self): @@ -103,8 +111,67 @@ class MacPort(base.Port): # to return something. return ('mac',) + def _skipped_file_paths(self): + # FIXME: This method will need to be made work for non-mac platforms and moved into base.Port. + skipped_files = [] + if self._name in ('mac-tiger', 'mac-leopard', 'mac-snowleopard'): + skipped_files.append(os.path.join( + self._webkit_baseline_path(self._name), 'Skipped')) + skipped_files.append(os.path.join(self._webkit_baseline_path('mac'), + 'Skipped')) + return skipped_files + + def _tests_for_other_platforms(self): + # The original run-webkit-tests builds up a "whitelist" of tests to run, and passes that to DumpRenderTree. + # run-chromium-webkit-tests assumes we run *all* tests and test_expectations.txt functions as a blacklist. + # FIXME: This list could be dynamic based on platform name and pushed into base.Port. + return [ + "platform/chromium", + "platform/gtk", + "platform/qt", + "platform/win", + ] + + def _tests_for_disabled_features(self): + # FIXME: This should use the feature detection from webkitperl/features.pm to match run-webkit-tests. + # For now we hard-code a list of features known to be disabled on the Mac platform. + disabled_feature_tests = [ + "fast/xhtmlmp", + "http/tests/wml", + "mathml", + "wml", + ] + # FIXME: webarchive tests expect to read-write from -expected.webarchive files instead of .txt files. + # This script doesn't know how to do that yet, so pretend they're just "disabled". + webarchive_tests = [ + "webarchive", + "svg/webarchive", + "http/tests/webarchive", + "svg/custom/image-with-prefix-in-webarchive.svg", + ] + return disabled_feature_tests + webarchive_tests + + def _tests_from_skipped_file(self, skipped_file): + tests_to_skip = [] + for line in skipped_file.readlines(): + line = line.strip() + if line.startswith('#') or not len(line): + continue + tests_to_skip.append(line) + return tests_to_skip + + def _expectations_from_skipped_files(self): + tests_to_skip = [] + for filename in self._skipped_file_paths(): + if not os.path.exists(filename): + logging.warn("Failed to open Skipped file: %s" % filename) + continue + skipped_file = file(filename) + tests_to_skip.extend(self._tests_from_skipped_file(skipped_file)) + skipped_file.close() + return tests_to_skip + def test_expectations(self): - # # The WebKit mac port uses 'Skipped' files at the moment. Each # file contains a list of files or directories to be skipped during # the test run. The total list of tests to skipped is given by the @@ -112,44 +179,11 @@ class MacPort(base.Port): # a version-specific file found in platform/X-version. Duplicate # entries are allowed. This routine reads those files and turns # contents into the format expected by test_expectations. - expectations = [] - skipped_files = [] - if self._name in ('mac-tiger', 'mac-leopard', 'mac-snowleopard'): - skipped_files.append(os.path.join( - self._webkit_baseline_path(self._name), 'Skipped')) - skipped_files.append(os.path.join(self._webkit_baseline_path('mac'), - 'Skipped')) - for filename in skipped_files: - if os.path.exists(filename): - f = file(filename) - for l in f.readlines(): - l = l.strip() - if not l.startswith('#') and len(l): - l = 'BUG_SKIPPED SKIP : ' + l + ' = FAIL' - if l not in expectations: - expectations.append(l) - f.close() - - # TODO - figure out how to check for these dynamically - expectations.append('BUG_SKIPPED SKIP : fast/wcss = FAIL') - expectations.append('BUG_SKIPPED SKIP : fast/xhtmlmp = FAIL') - expectations.append('BUG_SKIPPED SKIP : http/tests/wml = FAIL') - expectations.append('BUG_SKIPPED SKIP : mathml = FAIL') - expectations.append('BUG_SKIPPED SKIP : platform/chromium = FAIL') - expectations.append('BUG_SKIPPED SKIP : platform/gtk = FAIL') - expectations.append('BUG_SKIPPED SKIP : platform/qt = FAIL') - expectations.append('BUG_SKIPPED SKIP : platform/win = FAIL') - expectations.append('BUG_SKIPPED SKIP : wml = FAIL') - - # TODO - figure out how to handle webarchive tests - expectations.append('BUG_SKIPPED SKIP : webarchive = PASS') - expectations.append('BUG_SKIPPED SKIP : svg/webarchive = PASS') - expectations.append('BUG_SKIPPED SKIP : http/tests/webarchive = PASS') - expectations.append('BUG_SKIPPED SKIP : svg/custom/' - 'image-with-prefix-in-webarchive.svg = PASS') - - expectations_str = '\n'.join(expectations) - return expectations_str + tests_to_skip = set(self._expectations_from_skipped_files()) # Use a set to allow duplicates + tests_to_skip.update(self._tests_for_other_platforms()) + tests_to_skip.update(self._tests_for_disabled_features()) + expectations = map(lambda test_path: "BUG_SKIPPED SKIP : %s = FAIL" % test_path, tests_to_skip) + return "\n".join(expectations) def test_platform_name(self): # At the moment we don't use test platform names, but we have @@ -180,7 +214,7 @@ class MacPort(base.Port): def _build_path(self, *comps): if not self._cached_build_root: - self._cached_build_root = executive.run_command(["webkit-build-directory", "--base"]).rstrip() + self._cached_build_root = executive.run_command([self.script_path("webkit-build-directory"), "--top-level"]).rstrip() return os.path.join(self._cached_build_root, self._options.target, *comps) def _kill_process(self, pid): @@ -390,7 +424,6 @@ class MacDriver(base.Driver): return (crash, timeout, actual_image_hash, ''.join(output), ''.join(error)) - pass def stop(self): if self._proc: diff --git a/WebKitTools/Scripts/webkitpy/layout_tests/port/mac_unittest.py b/WebKitTools/Scripts/webkitpy/layout_tests/port/mac_unittest.py new file mode 100644 index 0000000..e47a4a4 --- /dev/null +++ b/WebKitTools/Scripts/webkitpy/layout_tests/port/mac_unittest.py @@ -0,0 +1,66 @@ +# 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 unittest +import mac +import StringIO + +class MacTest(unittest.TestCase): + + def test_skipped_file_paths(self): + port = mac.MacPort() + skipped_paths = port._skipped_file_paths() + # FIXME: _skipped_file_paths should return WebKit-relative paths. + # So to make it unit testable, we strip the WebKit directory from the path. + relative_paths = [path[len(port.path_from_webkit_base()):] for path in skipped_paths] + self.assertEqual(relative_paths, ['LayoutTests/platform/mac-leopard/Skipped', 'LayoutTests/platform/mac/Skipped']) + + example_skipped_file = """ +# <rdar://problem/5647952> fast/events/mouseout-on-window.html needs mac DRT to issue mouse out events +fast/events/mouseout-on-window.html + +# <rdar://problem/5643675> window.scrollTo scrolls a window with no scrollbars +fast/events/attempt-scroll-with-no-scrollbars.html + +# see bug <rdar://problem/5646437> REGRESSION (r28015): svg/batik/text/smallFonts fails +svg/batik/text/smallFonts.svg +""" + example_skipped_tests = [ + "fast/events/mouseout-on-window.html", + "fast/events/attempt-scroll-with-no-scrollbars.html", + "svg/batik/text/smallFonts.svg", + ] + + def test_skipped_file_paths(self): + port = mac.MacPort() + skipped_file = StringIO.StringIO(self.example_skipped_file) + self.assertEqual(port._tests_from_skipped_file(skipped_file), self.example_skipped_tests) + + +if __name__ == '__main__': + unittest.main() diff --git a/WebKitTools/Scripts/webkitpy/layout_tests/port/test.py b/WebKitTools/Scripts/webkitpy/layout_tests/port/test.py index 0bc6e7c..c3e97be 100644 --- a/WebKitTools/Scripts/webkitpy/layout_tests/port/test.py +++ b/WebKitTools/Scripts/webkitpy/layout_tests/port/test.py @@ -55,7 +55,8 @@ class TestPort(base.Port): def check_sys_deps(self): return True - def diff_image(self, actual_filename, expected_filename, diff_filename): + def diff_image(self, actual_filename, expected_filename, + diff_filename=None): return False def compare_text(self, actual_text, expected_text): diff --git a/WebKitTools/Scripts/webkitpy/layout_tests/port/websocket_server.py b/WebKitTools/Scripts/webkitpy/layout_tests/port/websocket_server.py index ba8a5e9..54c2f6f 100644 --- a/WebKitTools/Scripts/webkitpy/layout_tests/port/websocket_server.py +++ b/WebKitTools/Scripts/webkitpy/layout_tests/port/websocket_server.py @@ -159,6 +159,7 @@ class PyWebSocket(http_server.Lighttpd): '-p', str(self._port), '-d', self._layout_tests, '-s', self._web_socket_tests, + '-x', '/websocket/tests/cookies', '-l', error_log, ] 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 83cf99de..4604a1a 100644 --- a/WebKitTools/Scripts/webkitpy/layout_tests/rebaseline_chromium_webkit_tests.py +++ b/WebKitTools/Scripts/webkitpy/layout_tests/rebaseline_chromium_webkit_tests.py @@ -54,7 +54,7 @@ import urllib import webbrowser import zipfile -from layout_package import path_utils +import port from layout_package import test_expectations from test_types import image_diff from test_types import text_diff @@ -200,9 +200,10 @@ class Rebaseliner(object): REVISION_REGEX = r'<a href=\"(\d+)/\">' - def __init__(self, platform, options): - self._file_dir = path_utils.path_from_base('webkit', 'tools', + def __init__(self, port, platform, options): + self._file_dir = port.path_from_chromium_base('webkit', 'tools', 'layout_tests') + self._port = port self._platform = platform self._options = options self._rebaselining_tests = [] @@ -212,10 +213,12 @@ class Rebaseliner(object): # -. compile list of tests that need rebaselining. # -. update the tests in test_expectations file after rebaseline # is done. + expectations_str = self._port.test_expectations() self._test_expectations = \ - test_expectations.TestExpectations(None, - self._file_dir, - platform, + test_expectations.TestExpectations(self._port, + None, + expectations_str, + self._platform, False, False) @@ -359,7 +362,6 @@ class Rebaseliner(object): latest_revision = self._get_latest_revision(url_base) if latest_revision is None or latest_revision <= 0: return None - archive_url = ('%s%s/layout-test-results.zip' % (url_base, latest_revision)) logging.info('Archive url: "%s"', archive_url) @@ -399,7 +401,7 @@ class Rebaseliner(object): for name in zip_namelist: logging.debug(' ' + name) - platform = path_utils.platform_name(self._platform) + platform = self._port.name() logging.debug('Platform dir: "%s"', platform) test_no = 1 @@ -412,7 +414,7 @@ class Rebaseliner(object): test_basename = os.path.splitext(test)[0] for suffix in BASELINE_SUFFIXES: archive_test_name = ('layout-test-results/%s-actual%s' % - (test_basename, suffix)) + (test_basename, suffix)) logging.debug(' Archive test file name: "%s"', archive_test_name) if not archive_test_name in zip_namelist: @@ -431,7 +433,7 @@ class Rebaseliner(object): expected_filename = '%s-expected%s' % (test_basename, suffix) expected_fullpath = os.path.join( - path_utils.chromium_baseline_path(platform), + self._port._chromium_baseline_path(platform), expected_filename) expected_fullpath = os.path.normpath(expected_fullpath) logging.debug(' Expected file full path: "%s"', @@ -443,17 +445,17 @@ class Rebaseliner(object): # and lower # levels and remove all duplicated baselines. if self._is_dup_baseline(temp_name, - expected_fullpath, - test, - suffix, - self._platform): + expected_fullpath, + test, + suffix, + self._platform): os.remove(temp_name) self._delete_baseline(expected_fullpath) continue # Create the new baseline directory if it doesn't already # exist. - path_utils.maybe_make_directory( + self._port.maybe_make_directory( os.path.dirname(expected_fullpath)) shutil.move(temp_name, expected_fullpath) @@ -497,9 +499,9 @@ class Rebaseliner(object): True if the baseline is unnecessary. False otherwise. """ - test_filepath = os.path.join(path_utils.layout_tests_dir(), test) - all_baselines = path_utils.expected_baselines(test_filepath, - suffix, platform, True) + test_filepath = os.path.join(self._port.layout_tests_dir(), test) + all_baselines = self._port.expected_baselines(test_filepath, + suffix, True) for (fallback_dir, fallback_file) in all_baselines: if fallback_dir and fallback_file: fallback_fullpath = os.path.normpath( @@ -534,11 +536,11 @@ class Rebaseliner(object): return True if ext1 == '.PNG': - return image_diff.ImageDiff(self._platform, '').diff_files(file1, - file2) + return image_diff.ImageDiff(self._port, self._platform, + '').diff_files(self._port, file1, file2) else: - return text_diff.TestTextDiff(self._platform, '').diff_files(file1, - file2) + return text_diff.TestTextDiff(self._port, self._platform, + '').diff_files(self._port, file1, file2) def _delete_baseline(self, filename): """Remove the file from repository and delete it from disk. @@ -570,8 +572,21 @@ class Rebaseliner(object): """ if self._rebaselined_tests: - self._test_expectations.remove_platform_from_file( - self._rebaselined_tests, self._platform, backup) + new_expectations = ( + self._test_expectations.remove_platform_from_expectations( + self._rebaselined_tests, self._platform)) + path = self._port.path_to_test_expectations_file() + if backup: + date_suffix = time.strftime('%Y%m%d%H%M%S', + time.localtime(time.time())) + backup_file = ('%s.orig.%s' % (path, date_suffix)) + if os.path.exists(backup_file): + os.remove(backup_file) + logging.info('Saving original file to "%s"', backup_file) + os.rename(path, backup_file) + f = open(path, "w") + f.write(new_expectations) + f.close() else: logging.info('No test was rebaselined so nothing to remove.') @@ -777,8 +792,9 @@ class HtmlGenerator(object): '<img style="width: 200" src="%(uri)s" /></a></td>') HTML_TR = '<tr>%s</tr>' - def __init__(self, options, platforms, rebaselining_tests): + def __init__(self, port, options, platforms, rebaselining_tests): self._html_directory = options.html_directory + self._port = port self._platforms = platforms self._rebaselining_tests = rebaselining_tests self._html_file = os.path.join(options.html_directory, @@ -817,7 +833,7 @@ class HtmlGenerator(object): logging.info('Launching html: "%s"', self._html_file) - html_uri = path_utils.filename_to_uri(self._html_file) + html_uri = self._port.filename_to_uri(self._html_file) webbrowser.open(html_uri, 1) logging.info('Html launched.') @@ -855,13 +871,13 @@ class HtmlGenerator(object): links = '' if os.path.exists(old_file): links += html_td_link % { - 'uri': path_utils.filename_to_uri(old_file), + 'uri': self._port.filename_to_uri(old_file), 'name': baseline_filename} else: logging.info(' No old baseline file: "%s"', old_file) links += self.HTML_TD_NOLINK % '' - links += html_td_link % {'uri': path_utils.filename_to_uri(new_file), + links += html_td_link % {'uri': self._port.filename_to_uri(new_file), 'name': baseline_filename} diff_file = get_result_file_fullpath(self._html_directory, @@ -869,7 +885,7 @@ class HtmlGenerator(object): 'diff') logging.info(' Baseline diff file: "%s"', diff_file) if os.path.exists(diff_file): - links += html_td_link % {'uri': path_utils.filename_to_uri( + links += html_td_link % {'uri': self._port.filename_to_uri( diff_file), 'name': 'Diff'} else: logging.info(' No baseline diff file: "%s"', diff_file) @@ -908,8 +924,8 @@ class HtmlGenerator(object): rows.append(self.HTML_TR % row) if rows: - test_path = os.path.join(path_utils.layout_tests_dir(), test) - html = self.HTML_TR_TEST % (path_utils.filename_to_uri(test_path), + test_path = os.path.join(self._port.layout_tests_dir(), test) + html = self.HTML_TR_TEST % (self._port.filename_to_uri(test_path), test) html += self.HTML_TEST_DETAIL % ' '.join(rows) @@ -967,6 +983,7 @@ def main(): ' rebaselining comparison.')) options = option_parser.parse_args()[0] + port_obj = port.get(None, options) # Set up our logging format. log_level = logging.INFO @@ -1002,7 +1019,7 @@ def main(): rebaselining_tests = set() backup = options.backup for platform in rebaseline_platforms: - rebaseliner = Rebaseliner(platform, options) + rebaseliner = Rebaseliner(port_obj, platform, options) logging.info('') log_dashed_string('Rebaseline started', platform) @@ -1017,7 +1034,8 @@ def main(): logging.info('') log_dashed_string('Rebaselining result comparison started', None) - html_generator = HtmlGenerator(options, + html_generator = HtmlGenerator(port_obj, + options, rebaseline_platforms, rebaselining_tests) html_generator.generate_html() diff --git a/WebKitTools/Scripts/webkitpy/style/checker.py b/WebKitTools/Scripts/webkitpy/style/checker.py index fbda8cb..9beda9e 100644 --- a/WebKitTools/Scripts/webkitpy/style/checker.py +++ b/WebKitTools/Scripts/webkitpy/style/checker.py @@ -30,24 +30,24 @@ """Front end of some style-checker modules.""" import codecs -import getopt import os.path import sys from .. style_references import parse_patch from error_handlers import DefaultStyleErrorHandler from error_handlers import PatchStyleErrorHandler -from filter import validate_filter_rules from filter import FilterConfiguration +from optparser import ArgumentParser +from optparser import DefaultCommandOptionValues from processors.common import check_no_carriage_return from processors.common import categories as CommonCategories from processors.cpp import CppProcessor from processors.text import TextProcessor -# These defaults are used by check-webkit-style. -WEBKIT_DEFAULT_VERBOSITY = 1 -WEBKIT_DEFAULT_OUTPUT_FORMAT = 'emacs' +# These are default option values for the command-line option parser. +_DEFAULT_VERBOSITY = 1 +_DEFAULT_OUTPUT_FORMAT = 'emacs' # FIXME: For style categories we will never want to have, remove them. @@ -55,14 +55,16 @@ WEBKIT_DEFAULT_OUTPUT_FORMAT = 'emacs' # modify the implementation and enable them. # # Throughout this module, we use "filter rule" rather than "filter" -# for an individual boolean filter flag like "+foo". This allows us to +# for an individual boolean filter flag like "+foo". This allows us to # reserve "filter" for what one gets by collectively applying all of # the filter rules. # -# The _WEBKIT_FILTER_RULES are prepended to any user-specified filter -# rules. Since by default all errors are on, only include rules that -# begin with a - sign. -WEBKIT_DEFAULT_FILTER_RULES = [ +# The base filter rules are the filter rules that begin the list of +# filter rules used to check style. For example, these rules precede +# any user-specified filter rules. Since by default all categories are +# checked, this list should normally include only rules that begin +# with a "-" sign. +_BASE_FILTER_RULES = [ '-build/endif_comment', '-build/include_what_you_use', # <string> for std::string '-build/storage_class', # const static @@ -86,26 +88,24 @@ WEBKIT_DEFAULT_FILTER_RULES = [ ] -# FIXME: Change the second value of each tuple from a tuple to a list, -# and alter the filter code so it accepts lists instead. (The -# filter code will need to convert incoming values from a list -# to a tuple prior to caching). This will make this -# configuration setting a bit simpler since tuples have an -# unusual syntax case. -# # The path-specific filter rules. # # This list is order sensitive. Only the first path substring match # is used. See the FilterConfiguration documentation in filter.py # for more information on this list. +# +# Each string appearing in this nested list should have at least +# one associated unit test assertion. These assertions are located, +# for example, in the test_path_rules_specifier() unit test method of +# checker_unittest.py. _PATH_RULES_SPECIFIER = [ # Files in these directories are consumers of the WebKit # API and therefore do not follow the same header including # discipline as WebCore. (["WebKitTools/WebKitAPITest/", "WebKit/qt/QGVLauncher/"], - ("-build/include", - "-readability/streams")), + ["-build/include", + "-readability/streams"]), ([# The GTK+ APIs use GTK+ naming style, which includes # lower-cased, underscore-separated values. "WebKit/gtk/webkit/", @@ -116,13 +116,7 @@ _PATH_RULES_SPECIFIER = [ # QtTest module. "WebKit/qt/tests/", "JavaScriptCore/qt/tests"], - ("-readability/naming",)), - # These are test file patterns. - (["_test.cpp", - "_unittest.cpp", - "_regtest.cpp"], - ("-readability/streams", # Many unit tests use cout. - "-runtime/rtti")), + ["-readability/naming"]), ] @@ -131,7 +125,7 @@ _PATH_RULES_SPECIFIER = [ # future merges. # # Include a warning for skipped files that are less obvious. -SKIPPED_FILES_WITH_WARNING = [ +_SKIPPED_FILES_WITH_WARNING = [ # The Qt API and tests do not follow WebKit style. # They follow Qt style. :) "gtk2drawing.c", # WebCore/platform/gtk/gtk2drawing.c @@ -145,439 +139,56 @@ SKIPPED_FILES_WITH_WARNING = [ # Don't include a warning for skipped files that are more common # and more obvious. -SKIPPED_FILES_WITHOUT_WARNING = [ +_SKIPPED_FILES_WITHOUT_WARNING = [ "LayoutTests/" ] # The maximum number of errors to report per file, per category. # If a category is not a key, then it has no maximum. -MAX_REPORTS_PER_CATEGORY = { +_MAX_REPORTS_PER_CATEGORY = { "whitespace/carriage_return": 1 } -def style_categories(): +def _all_categories(): """Return the set of all categories used by check-webkit-style.""" # Take the union across all processors. return CommonCategories.union(CppProcessor.categories) -def webkit_argument_defaults(): - """Return the DefaultArguments instance for use by check-webkit-style.""" - return ArgumentDefaults(WEBKIT_DEFAULT_OUTPUT_FORMAT, - WEBKIT_DEFAULT_VERBOSITY, - WEBKIT_DEFAULT_FILTER_RULES) - - -def _create_usage(defaults): - """Return the usage string to display for command help. - - Args: - defaults: An ArgumentDefaults instance. - - """ - usage = """ -Syntax: %(program_name)s [--verbose=#] [--git-commit=<SingleCommit>] [--output=vs7] - [--filter=-x,+y,...] [file] ... - - The style guidelines this tries to follow are here: - http://webkit.org/coding/coding-style.html - - Every style error is given a confidence score from 1-5, with 5 meaning - we are certain of the problem, and 1 meaning it could be a legitimate - construct. This can miss some errors and does not substitute for - code review. - - To prevent specific lines from being linted, add a '// NOLINT' comment to the - end of the line. - - Linted extensions are .cpp, .c and .h. Other file types are ignored. - - The file parameter is optional and accepts multiple files. Leaving - out the file parameter applies the check to all files considered changed - by your source control management system. - - Flags: - - verbose=# - A number 1-5 that restricts output to errors with a confidence - score at or above this value. In particular, the value 1 displays - all errors. The default is %(default_verbosity)s. - - git-commit=<SingleCommit> - Checks the style of everything from the given commit to the local tree. - - output=vs7 - The output format, which may be one of - emacs : to ease emacs parsing - vs7 : compatible with Visual Studio - Defaults to "%(default_output_format)s". Other formats are unsupported. - - filter=-x,+y,... - A comma-separated list of boolean filter rules used to filter - which categories of style guidelines to check. The script checks - a category if the category passes the filter rules, as follows. - - Any webkit category starts out passing. All filter rules are then - evaluated left to right, with later rules taking precedence. For - example, the rule "+foo" passes any category that starts with "foo", - and "-foo" fails any such category. The filter input "-whitespace, - +whitespace/braces" fails the category "whitespace/tab" and passes - "whitespace/braces". - - Examples: --filter=-whitespace,+whitespace/braces - --filter=-whitespace,-runtime/printf,+runtime/printf_format - --filter=-,+build/include_what_you_use - - Category names appear in error messages in brackets, for example - [whitespace/indent]. To see a list of all categories available to - %(program_name)s, along with which are enabled by default, pass - the empty filter as follows: - --filter= -""" % {'program_name': os.path.basename(sys.argv[0]), - 'default_verbosity': defaults.verbosity, - 'default_output_format': defaults.output_format} - - return usage - - -# FIXME: Eliminate support for "extra_flag_values". -# -# FIXME: Remove everything from ProcessorOptions except for the -# information that can be passed via the command line, and -# rename to something like CheckWebKitStyleOptions. This -# includes, but is not limited to, removing the -# max_reports_per_error attribute and the is_reportable() -# method. See also the FIXME below to create a new class -# called something like CheckerConfiguration. -# -# This class should not have knowledge of the flag key names. -class ProcessorOptions(object): - - """A container to store options passed via the command line. - - Attributes: - extra_flag_values: A string-string dictionary of all flag key-value - pairs that are not otherwise represented by this - class. The default is the empty dictionary. - - filter_configuration: A FilterConfiguration instance. The default - is the "empty" filter configuration, which - means that all errors should be checked. - - git_commit: A string representing the git commit to check. - The default is None. - - max_reports_per_error: The maximum number of errors to report - per file, per category. - - output_format: A string that is the output format. The supported - output formats are "emacs" which emacs can parse - and "vs7" which Microsoft Visual Studio 7 can parse. - - verbosity: An integer between 1-5 inclusive that restricts output - to errors with a confidence score at or above this value. - The default is 1, which reports all errors. - - """ - def __init__(self, - extra_flag_values=None, - filter_configuration = None, - git_commit=None, - max_reports_per_category=None, - output_format="emacs", - verbosity=1): - if extra_flag_values is None: - extra_flag_values = {} - if filter_configuration is None: - filter_configuration = FilterConfiguration() - if max_reports_per_category is None: - max_reports_per_category = {} - - if output_format not in ("emacs", "vs7"): - raise ValueError('Invalid "output_format" parameter: ' - 'value must be "emacs" or "vs7". ' - 'Value given: "%s".' % output_format) - - if (verbosity < 1) or (verbosity > 5): - raise ValueError('Invalid "verbosity" parameter: ' - "value must be an integer between 1-5 inclusive. " - 'Value given: "%s".' % verbosity) - - self.extra_flag_values = extra_flag_values - self.filter_configuration = filter_configuration - self.git_commit = git_commit - self.max_reports_per_category = max_reports_per_category - self.output_format = output_format - self.verbosity = verbosity - - # Useful for unit testing. - def __eq__(self, other): - """Return whether this ProcessorOptions instance is equal to another.""" - if self.extra_flag_values != other.extra_flag_values: - return False - if self.filter_configuration != other.filter_configuration: - return False - if self.git_commit != other.git_commit: - return False - if self.max_reports_per_category != other.max_reports_per_category: - return False - if self.output_format != other.output_format: - return False - if self.verbosity != other.verbosity: - return False - - return True - - # Useful for unit testing. - def __ne__(self, other): - # Python does not automatically deduce this from __eq__(). - return not self.__eq__(other) - - def is_reportable(self, category, confidence_in_error, path): - """Return whether an error is reportable. - - An error is reportable if the confidence in the error - is at least the current verbosity level, and if the current - filter says that the category should be checked for the - given path. - - Args: - category: A string that is a style category. - confidence_in_error: An integer between 1 and 5, inclusive, that - represents the application's confidence in - the error. A higher number signifies greater - confidence. - path: The path of the file being checked - - """ - if confidence_in_error < self.verbosity: - return False - - return self.filter_configuration.should_check(category, path) - - -# This class should not have knowledge of the flag key names. -class ArgumentDefaults(object): - - """A container to store default argument values. - - Attributes: - output_format: A string that is the default output format. - verbosity: An integer that is the default verbosity level. - base_filter_rules: A list of strings that are boolean filter rules - to prepend to any user-specified rules. - - """ - - def __init__(self, default_output_format, default_verbosity, - default_base_filter_rules): - self.output_format = default_output_format - self.verbosity = default_verbosity - self.base_filter_rules = default_base_filter_rules - - -class ArgumentPrinter(object): - - """Supports the printing of check-webkit-style command arguments.""" - - def _flag_pair_to_string(self, flag_key, flag_value): - return '--%(key)s=%(val)s' % {'key': flag_key, 'val': flag_value } - - def to_flag_string(self, options): - """Return a flag string yielding the given ProcessorOptions instance. - - This method orders the flag values alphabetically by the flag key. - - Args: - options: A ProcessorOptions instance. - - """ - flags = options.extra_flag_values.copy() +def _check_webkit_style_defaults(): + """Return the default command-line options for check-webkit-style.""" + return DefaultCommandOptionValues(output_format=_DEFAULT_OUTPUT_FORMAT, + verbosity=_DEFAULT_VERBOSITY) - flags['output'] = options.output_format - flags['verbose'] = options.verbosity - # Only include the filter flag if user-provided rules are present. - user_rules = options.filter_configuration.user_rules - if user_rules: - flags['filter'] = ",".join(user_rules) - if options.git_commit: - flags['git-commit'] = options.git_commit - flag_string = '' - # Alphabetizing lets us unit test this method. - for key in sorted(flags.keys()): - flag_string += self._flag_pair_to_string(key, flags[key]) + ' ' +# This function assists in optparser not having to import from checker. +def check_webkit_style_parser(): + all_categories = _all_categories() + default_options = _check_webkit_style_defaults() + return ArgumentParser(all_categories=all_categories, + base_filter_rules=_BASE_FILTER_RULES, + default_options=default_options) - return flag_string.strip() +def check_webkit_style_configuration(options): + """Return a StyleCheckerConfiguration instance for check-webkit-style. -class ArgumentParser(object): - - """Supports the parsing of check-webkit-style command arguments. - - Attributes: - defaults: An ArgumentDefaults instance. - create_usage: A function that accepts an ArgumentDefaults instance - and returns a string of usage instructions. - This defaults to the function used to generate the - usage string for check-webkit-style. - doc_print: A function that accepts a string parameter and that is - called to display help messages. This defaults to - sys.stderr.write(). + Args: + options: A CommandOptionValues instance. """ + filter_configuration = FilterConfiguration( + base_rules=_BASE_FILTER_RULES, + path_specific=_PATH_RULES_SPECIFIER, + user_rules=options.filter_rules) - def __init__(self, argument_defaults, create_usage=None, doc_print=None): - if create_usage is None: - create_usage = _create_usage - if doc_print is None: - doc_print = sys.stderr.write - - self.defaults = argument_defaults - self.create_usage = create_usage - self.doc_print = doc_print - - def _exit_with_usage(self, error_message=''): - """Exit and print a usage string with an optional error message. - - Args: - error_message: A string that is an error message to print. - - """ - usage = self.create_usage(self.defaults) - self.doc_print(usage) - if error_message: - sys.exit('\nFATAL ERROR: ' + error_message) - else: - sys.exit(1) - - def _exit_with_categories(self): - """Exit and print the style categories and default filter rules.""" - self.doc_print('\nAll categories:\n') - categories = style_categories() - for category in sorted(categories): - self.doc_print(' ' + category + '\n') - - self.doc_print('\nDefault filter rules**:\n') - for filter_rule in sorted(self.defaults.base_filter_rules): - self.doc_print(' ' + filter_rule + '\n') - self.doc_print('\n**The command always evaluates the above rules, ' - 'and before any --filter flag.\n\n') - - sys.exit(0) - - def _parse_filter_flag(self, flag_value): - """Parse the --filter flag, and return a list of filter rules. - - Args: - flag_value: A string of comma-separated filter rules, for - example "-whitespace,+whitespace/indent". - - """ - filters = [] - for uncleaned_filter in flag_value.split(','): - filter = uncleaned_filter.strip() - if not filter: - continue - filters.append(filter) - return filters - - def parse(self, args, extra_flags=None): - """Parse the command line arguments to check-webkit-style. - - Args: - args: A list of command-line arguments as returned by sys.argv[1:]. - extra_flags: A list of flags whose values we want to extract, but - are not supported by the ProcessorOptions class. - An example flag "new_flag=". This defaults to the - empty list. - - Returns: - A tuple of (filenames, options) - - filenames: The list of filenames to check. - options: A ProcessorOptions instance. - - """ - if extra_flags is None: - extra_flags = [] - - output_format = self.defaults.output_format - verbosity = self.defaults.verbosity - base_rules = self.defaults.base_filter_rules - - # The flags already supported by the ProcessorOptions class. - flags = ['help', 'output=', 'verbose=', 'filter=', 'git-commit='] - - for extra_flag in extra_flags: - if extra_flag in flags: - raise ValueError('Flag \'%(extra_flag)s is duplicated ' - 'or already supported.' % - {'extra_flag': extra_flag}) - flags.append(extra_flag) - - try: - (opts, filenames) = getopt.getopt(args, '', flags) - except getopt.GetoptError: - # FIXME: Settle on an error handling approach: come up - # with a consistent guideline as to when and whether - # a ValueError should be raised versus calling - # sys.exit when needing to interrupt execution. - self._exit_with_usage('Invalid arguments.') - - extra_flag_values = {} - git_commit = None - user_rules = [] - - for (opt, val) in opts: - if opt == '--help': - self._exit_with_usage() - elif opt == '--output': - output_format = val - elif opt == '--verbose': - verbosity = val - elif opt == '--git-commit': - git_commit = val - elif opt == '--filter': - if not val: - self._exit_with_categories() - # Prepend the defaults. - user_rules = self._parse_filter_flag(val) - else: - extra_flag_values[opt] = val - - # Check validity of resulting values. - if filenames and (git_commit != None): - self._exit_with_usage('It is not possible to check files and a ' - 'specific commit at the same time.') - - if output_format not in ('emacs', 'vs7'): - raise ValueError('Invalid --output value "%s": The only ' - 'allowed output formats are emacs and vs7.' % - output_format) - - all_categories = style_categories() - validate_filter_rules(user_rules, all_categories) - - verbosity = int(verbosity) - if (verbosity < 1) or (verbosity > 5): - raise ValueError('Invalid --verbose value %s: value must ' - 'be between 1-5.' % verbosity) - - filter_configuration = FilterConfiguration(base_rules=base_rules, - path_specific=_PATH_RULES_SPECIFIER, - user_rules=user_rules) - - options = ProcessorOptions(extra_flag_values=extra_flag_values, - filter_configuration=filter_configuration, - git_commit=git_commit, - max_reports_per_category=MAX_REPORTS_PER_CATEGORY, - output_format=output_format, - verbosity=verbosity) - - return (filenames, options) + return StyleCheckerConfiguration(filter_configuration=filter_configuration, + max_reports_per_category=_MAX_REPORTS_PER_CATEGORY, + output_format=options.output_format, + stderr_write=sys.stderr.write, + verbosity=options.verbosity) # Enum-like idiom @@ -617,14 +228,14 @@ class ProcessorDispatcher(object): def should_skip_with_warning(self, file_path): """Return whether the given file should be skipped with a warning.""" - for skipped_file in SKIPPED_FILES_WITH_WARNING: + for skipped_file in _SKIPPED_FILES_WITH_WARNING: if file_path.find(skipped_file) >= 0: return True return False def should_skip_without_warning(self, file_path): """Return whether the given file should be skipped without a warning.""" - for skipped_file in SKIPPED_FILES_WITHOUT_WARNING: + for skipped_file in _SKIPPED_FILES_WITHOUT_WARNING: if file_path.find(skipped_file) >= 0: return True return False @@ -678,16 +289,95 @@ class ProcessorDispatcher(object): return processor -# FIXME: When creating the new CheckWebKitStyleOptions class as -# described in a FIXME above, add a new class here called -# something like CheckerConfiguration. The class should contain -# attributes for options needed to process a file. This includes -# a subset of the CheckWebKitStyleOptions attributes, a -# FilterConfiguration attribute, an stderr_write attribute, a -# max_reports_per_category attribute, etc. It can also include -# the is_reportable() method. The StyleChecker should accept -# an instance of this class rather than a ProcessorOptions -# instance. +class StyleCheckerConfiguration(object): + + """Stores configuration values for the StyleChecker class. + + Attributes: + max_reports_per_category: The maximum number of errors to report + per category, per file. + + stderr_write: A function that takes a string as a parameter and + serves as stderr.write. + + verbosity: An integer between 1-5 inclusive that restricts output + to errors with a confidence score at or above this value. + + """ + + def __init__(self, + filter_configuration, + max_reports_per_category, + output_format, + stderr_write, + verbosity): + """Create a StyleCheckerConfiguration instance. + + Args: + filter_configuration: A FilterConfiguration instance. The default + is the "empty" filter configuration, which + means that all errors should be checked. + + max_reports_per_category: The maximum number of errors to report + per category, per file. + + output_format: A string that is the output format. The supported + output formats are "emacs" which emacs can parse + and "vs7" which Microsoft Visual Studio 7 can parse. + + stderr_write: A function that takes a string as a parameter and + serves as stderr.write. + + verbosity: An integer between 1-5 inclusive that restricts output + to errors with a confidence score at or above this value. + The default is 1, which reports all errors. + + """ + self._filter_configuration = filter_configuration + self._output_format = output_format + + self.max_reports_per_category = max_reports_per_category + self.stderr_write = stderr_write + self.verbosity = verbosity + + def is_reportable(self, category, confidence_in_error, file_path): + """Return whether an error is reportable. + + An error is reportable if both the confidence in the error is + at least the current verbosity level and the current filter + says the category should be checked for the given path. + + Args: + category: A string that is a style category. + confidence_in_error: An integer between 1 and 5, inclusive, that + represents the application's confidence in + the error. A higher number signifies greater + confidence. + file_path: The path of the file being checked + + """ + if confidence_in_error < self.verbosity: + return False + + return self._filter_configuration.should_check(category, file_path) + + def write_style_error(self, + category, + confidence, + file_path, + line_number, + message): + """Write a style error to the configured stderr.""" + if self._output_format == 'vs7': + format_string = "%s(%s): %s [%s] [%d]\n" + else: + format_string = "%s:%s: %s [%s] [%d]\n" + + self.stderr_write(format_string % (file_path, + line_number, + message, + category, + confidence)) class StyleChecker(object): @@ -698,28 +388,26 @@ class StyleChecker(object): error_count: An integer that is the total number of reported errors for the lifetime of this StyleChecker instance. - options: A ProcessorOptions instance that controls the behavior - of style checking. + file_count: An integer that is the total number of processed + files. Note that the number of skipped files is + included in this value. """ - def __init__(self, options, stderr_write=None): + def __init__(self, configuration): """Create a StyleChecker instance. Args: - options: See options attribute. - stderr_write: A function that takes a string as a parameter - and that is called when a style error occurs. - Defaults to sys.stderr.write. This should be - used only for unit tests. + configuration: A StyleCheckerConfiguration instance that controls + the behavior of style checking. """ - if stderr_write is None: - stderr_write = sys.stderr.write - - self._stderr_write = stderr_write + self._configuration = configuration self.error_count = 0 - self.options = options + self.file_count = 0 + + def _stderr_write(self, message): + self._configuration.stderr_write(message) def _increment_error_count(self): """Increment the total count of reported errors.""" @@ -784,13 +472,16 @@ class StyleChecker(object): """ if handle_style_error is None: - handle_style_error = DefaultStyleErrorHandler(file_path, - self.options, - self._increment_error_count, - self._stderr_write) + handle_style_error = DefaultStyleErrorHandler( + configuration=self._configuration, + file_path=file_path, + increment_error_count= + self._increment_error_count) if process_file is None: process_file = self._process_file + self.file_count += 1 + dispatcher = ProcessorDispatcher() if dispatcher.should_skip_without_warning(file_path): @@ -800,7 +491,7 @@ class StyleChecker(object): "style guide.\n" % file_path) return - verbosity = self.options.verbosity + verbosity = self._configuration.verbosity processor = dispatcher.dispatch_processor(file_path, handle_style_error, verbosity) @@ -820,9 +511,7 @@ class StyleChecker(object): for file_path, diff in patch_files.iteritems(): style_error_handler = PatchStyleErrorHandler(diff, file_path, - self.options, - self._increment_error_count, - self._stderr_write) + self._configuration, + self._increment_error_count) self.check_file(file_path, style_error_handler) - diff --git a/WebKitTools/Scripts/webkitpy/style/checker_unittest.py b/WebKitTools/Scripts/webkitpy/style/checker_unittest.py index e1c9baf..fe12512 100755 --- a/WebKitTools/Scripts/webkitpy/style/checker_unittest.py +++ b/WebKitTools/Scripts/webkitpy/style/checker_unittest.py @@ -37,119 +37,40 @@ import unittest import checker as style +from checker import _BASE_FILTER_RULES +from checker import _MAX_REPORTS_PER_CATEGORY from checker import _PATH_RULES_SPECIFIER as PATH_RULES_SPECIFIER -from checker import style_categories +from checker import _all_categories +from checker import check_webkit_style_configuration +from checker import check_webkit_style_parser from checker import ProcessorDispatcher -from checker import ProcessorOptions from checker import StyleChecker +from checker import StyleCheckerConfiguration from filter import validate_filter_rules from filter import FilterConfiguration +from optparser import ArgumentParser +from optparser import CommandOptionValues from processors.cpp import CppProcessor from processors.text import TextProcessor -class ProcessorOptionsTest(unittest.TestCase): - - """Tests ProcessorOptions class.""" - - def test_init(self): - """Test __init__ constructor.""" - # Check default parameters. - options = ProcessorOptions() - self.assertEquals(options.extra_flag_values, {}) - self.assertEquals(options.filter_configuration, FilterConfiguration()) - self.assertEquals(options.git_commit, None) - self.assertEquals(options.max_reports_per_category, {}) - self.assertEquals(options.output_format, "emacs") - self.assertEquals(options.verbosity, 1) - - # Check argument validation. - self.assertRaises(ValueError, ProcessorOptions, output_format="bad") - ProcessorOptions(output_format="emacs") # No ValueError: works - ProcessorOptions(output_format="vs7") # works - self.assertRaises(ValueError, ProcessorOptions, verbosity=0) - self.assertRaises(ValueError, ProcessorOptions, verbosity=6) - ProcessorOptions(verbosity=1) # works - ProcessorOptions(verbosity=5) # works - - # Check attributes. - filter_configuration = FilterConfiguration(base_rules=["+"]) - options = ProcessorOptions(extra_flag_values={"extra_value" : 2}, - filter_configuration=filter_configuration, - git_commit="commit", - max_reports_per_category={"category": 3}, - output_format="vs7", - verbosity=3) - self.assertEquals(options.extra_flag_values, {"extra_value" : 2}) - self.assertEquals(options.filter_configuration, filter_configuration) - self.assertEquals(options.git_commit, "commit") - self.assertEquals(options.max_reports_per_category, {"category": 3}) - self.assertEquals(options.output_format, "vs7") - self.assertEquals(options.verbosity, 3) - - def test_eq(self): - """Test __eq__ equality function.""" - # == calls __eq__. - self.assertTrue(ProcessorOptions() == ProcessorOptions()) - - # Verify that a difference in any argument causes equality to fail. - filter_configuration = FilterConfiguration(base_rules=["+"]) - options = ProcessorOptions(extra_flag_values={"extra_value" : 1}, - filter_configuration=filter_configuration, - git_commit="commit", - max_reports_per_category={"category": 3}, - output_format="vs7", - verbosity=1) - self.assertFalse(options == ProcessorOptions(extra_flag_values={"extra_value" : 2})) - new_config = FilterConfiguration(base_rules=["-"]) - self.assertFalse(options == - ProcessorOptions(filter_configuration=new_config)) - self.assertFalse(options == ProcessorOptions(git_commit="commit2")) - self.assertFalse(options == ProcessorOptions(max_reports_per_category= - {"category": 2})) - self.assertFalse(options == ProcessorOptions(output_format="emacs")) - self.assertFalse(options == ProcessorOptions(verbosity=2)) - - def test_ne(self): - """Test __ne__ inequality function.""" - # != calls __ne__. - # By default, __ne__ always returns true on different objects. - # Thus, just check the distinguishing case to verify that the - # code defines __ne__. - self.assertFalse(ProcessorOptions() != ProcessorOptions()) - - def test_is_reportable(self): - """Test is_reportable().""" - filter_configuration = FilterConfiguration(base_rules=["-xyz"]) - options = ProcessorOptions(filter_configuration=filter_configuration, - verbosity=3) - - # Test verbosity - self.assertTrue(options.is_reportable("abc", 3, "foo.h")) - self.assertFalse(options.is_reportable("abc", 2, "foo.h")) - - # Test filter - self.assertTrue(options.is_reportable("xy", 3, "foo.h")) - self.assertFalse(options.is_reportable("xyz", 3, "foo.h")) - - class GlobalVariablesTest(unittest.TestCase): """Tests validity of the global variables.""" def _all_categories(self): - return style.style_categories() + return _all_categories() def defaults(self): - return style.webkit_argument_defaults() + return style._check_webkit_style_defaults() - def test_filter_rules(self): + def test_webkit_base_filter_rules(self): + base_filter_rules = _BASE_FILTER_RULES defaults = self.defaults() already_seen = [] - validate_filter_rules(defaults.base_filter_rules, - self._all_categories()) + validate_filter_rules(base_filter_rules, self._all_categories()) # Also do some additional checks. - for rule in defaults.base_filter_rules: + for rule in base_filter_rules: # Check no leading or trailing white space. self.assertEquals(rule, rule.strip()) # All categories are on by default, so defaults should @@ -161,203 +82,77 @@ class GlobalVariablesTest(unittest.TestCase): def test_defaults(self): """Check that default arguments are valid.""" - defaults = self.defaults() + default_options = self.defaults() # FIXME: We should not need to call parse() to determine # whether the default arguments are valid. - parser = style.ArgumentParser(defaults) + parser = ArgumentParser(all_categories=self._all_categories(), + base_filter_rules=[], + default_options=default_options) # No need to test the return value here since we test parse() # on valid arguments elsewhere. parser.parse([]) # arguments valid: no error or SystemExit def test_path_rules_specifier(self): - all_categories = style_categories() + all_categories = self._all_categories() for (sub_paths, path_rules) in PATH_RULES_SPECIFIER: - self.assertTrue(isinstance(path_rules, tuple), - "Checking: " + str(path_rules)) validate_filter_rules(path_rules, self._all_categories()) - # Try using the path specifier (as an "end-to-end" check). config = FilterConfiguration(path_specific=PATH_RULES_SPECIFIER) - self.assertTrue(config.should_check("xxx_any_category", - "xxx_non_matching_path")) - self.assertTrue(config.should_check("xxx_any_category", - "WebKitTools/WebKitAPITest/")) - self.assertFalse(config.should_check("build/include", - "WebKitTools/WebKitAPITest/")) - self.assertFalse(config.should_check("readability/naming", - "WebKit/qt/tests/qwebelement/tst_qwebelement.cpp")) + + def assertCheck(path, category): + """Assert that the given category should be checked.""" + message = ('Should check category "%s" for path "%s".' + % (category, path)) + self.assertTrue(config.should_check(category, path)) + + def assertNoCheck(path, category): + """Assert that the given category should not be checked.""" + message = ('Should not check category "%s" for path "%s".' + % (category, path)) + self.assertFalse(config.should_check(category, path), message) + + assertCheck("random_path.cpp", + "build/include") + assertNoCheck("WebKitTools/WebKitAPITest/main.cpp", + "build/include") + assertNoCheck("WebKit/qt/QGVLauncher/main.cpp", + "build/include") + assertNoCheck("WebKit/qt/QGVLauncher/main.cpp", + "readability/streams") + + assertCheck("random_path.cpp", + "readability/naming") + assertNoCheck("WebKit/gtk/webkit/webkit.h", + "readability/naming") + assertNoCheck("WebCore/css/CSSParser.cpp", + "readability/naming") + assertNoCheck("WebKit/qt/tests/qwebelement/tst_qwebelement.cpp", + "readability/naming") + assertNoCheck( + "JavaScriptCore/qt/tests/qscriptengine/tst_qscriptengine.cpp", + "readability/naming") def test_max_reports_per_category(self): - """Check that MAX_REPORTS_PER_CATEGORY is valid.""" + """Check that _MAX_REPORTS_PER_CATEGORY is valid.""" all_categories = self._all_categories() - for category in style.MAX_REPORTS_PER_CATEGORY.iterkeys(): + for category in _MAX_REPORTS_PER_CATEGORY.iterkeys(): self.assertTrue(category in all_categories, 'Key "%s" is not a category' % category) -class ArgumentPrinterTest(unittest.TestCase): - - """Tests the ArgumentPrinter class.""" - - _printer = style.ArgumentPrinter() - - def _create_options(self, - output_format='emacs', - verbosity=3, - user_rules=[], - git_commit=None, - extra_flag_values={}): - filter_configuration = FilterConfiguration(user_rules=user_rules) - return style.ProcessorOptions(extra_flag_values=extra_flag_values, - filter_configuration=filter_configuration, - git_commit=git_commit, - output_format=output_format, - verbosity=verbosity) +class CheckWebKitStyleFunctionTest(unittest.TestCase): + + """Tests the functions with names of the form check_webkit_style_*.""" + + def test_check_webkit_style_configuration(self): + # Exercise the code path to make sure the function does not error out. + option_values = CommandOptionValues() + configuration = check_webkit_style_configuration(option_values) - def test_to_flag_string(self): - options = self._create_options('vs7', 5, ['+foo', '-bar'], 'git', - {'a': 0, 'z': 1}) - self.assertEquals('--a=0 --filter=+foo,-bar --git-commit=git ' - '--output=vs7 --verbose=5 --z=1', - self._printer.to_flag_string(options)) - - # This is to check that --filter and --git-commit do not - # show up when not user-specified. - options = self._create_options() - self.assertEquals('--output=emacs --verbose=3', - self._printer.to_flag_string(options)) - - -class ArgumentParserTest(unittest.TestCase): - - """Test the ArgumentParser class.""" - - def _parse(self): - """Return a default parse() function for testing.""" - return self._create_parser().parse - - def _create_defaults(self, default_output_format='vs7', - default_verbosity=3, - default_filter_rules=['-', '+whitespace']): - """Return a default ArgumentDefaults instance for testing.""" - return style.ArgumentDefaults(default_output_format, - default_verbosity, - default_filter_rules) - - def _create_parser(self, defaults=None): - """Return an ArgumentParser instance for testing.""" - def create_usage(_defaults): - """Return a usage string for testing.""" - return "usage" - - def doc_print(message): - # We do not want the usage string or style categories - # to print during unit tests, so print nothing. - return - - if defaults is None: - defaults = self._create_defaults() - - return style.ArgumentParser(defaults, create_usage, doc_print) - - def test_parse_documentation(self): - parse = self._parse() - - # FIXME: Test both the printing of the usage string and the - # filter categories help. - - # Request the usage string. - self.assertRaises(SystemExit, parse, ['--help']) - # Request default filter rules and available style categories. - self.assertRaises(SystemExit, parse, ['--filter=']) - - def test_parse_bad_values(self): - parse = self._parse() - - # Pass an unsupported argument. - self.assertRaises(SystemExit, parse, ['--bad']) - - self.assertRaises(ValueError, parse, ['--verbose=bad']) - self.assertRaises(ValueError, parse, ['--verbose=0']) - self.assertRaises(ValueError, parse, ['--verbose=6']) - parse(['--verbose=1']) # works - parse(['--verbose=5']) # works - - self.assertRaises(ValueError, parse, ['--output=bad']) - parse(['--output=vs7']) # works - - # Pass a filter rule not beginning with + or -. - self.assertRaises(ValueError, parse, ['--filter=build']) - parse(['--filter=+build']) # works - # Pass files and git-commit at the same time. - self.assertRaises(SystemExit, parse, ['--git-commit=', 'file.txt']) - # Pass an extra flag already supported. - self.assertRaises(ValueError, parse, [], ['filter=']) - parse([], ['extra=']) # works - # Pass an extra flag with typo. - self.assertRaises(SystemExit, parse, ['--extratypo='], ['extra=']) - parse(['--extra='], ['extra=']) # works - self.assertRaises(ValueError, parse, [], ['extra=', 'extra=']) - - - def test_parse_default_arguments(self): - parse = self._parse() - - (files, options) = parse([]) - - self.assertEquals(files, []) - - self.assertEquals(options.output_format, 'vs7') - self.assertEquals(options.verbosity, 3) - self.assertEquals(options.filter_configuration, - FilterConfiguration(base_rules=["-", "+whitespace"], - path_specific=PATH_RULES_SPECIFIER)) - self.assertEquals(options.git_commit, None) - - def test_parse_explicit_arguments(self): - parse = self._parse() - - # Pass non-default explicit values. - (files, options) = parse(['--output=emacs']) - self.assertEquals(options.output_format, 'emacs') - (files, options) = parse(['--verbose=4']) - self.assertEquals(options.verbosity, 4) - (files, options) = parse(['--git-commit=commit']) - self.assertEquals(options.git_commit, 'commit') - - # Pass user_rules. - (files, options) = parse(['--filter=+build,-whitespace']) - config = options.filter_configuration - self.assertEquals(options.filter_configuration, - FilterConfiguration(base_rules=["-", "+whitespace"], - path_specific=PATH_RULES_SPECIFIER, - user_rules=["+build", "-whitespace"])) - - # Pass spurious white space in user rules. - (files, options) = parse(['--filter=+build, -whitespace']) - self.assertEquals(options.filter_configuration, - FilterConfiguration(base_rules=["-", "+whitespace"], - path_specific=PATH_RULES_SPECIFIER, - user_rules=["+build", "-whitespace"])) - - # Pass extra flag values. - (files, options) = parse(['--extra'], ['extra']) - self.assertEquals(options.extra_flag_values, {'--extra': ''}) - (files, options) = parse(['--extra='], ['extra=']) - self.assertEquals(options.extra_flag_values, {'--extra': ''}) - (files, options) = parse(['--extra=x'], ['extra=']) - self.assertEquals(options.extra_flag_values, {'--extra': 'x'}) - - def test_parse_files(self): - parse = self._parse() - - (files, options) = parse(['foo.cpp']) - self.assertEquals(files, ['foo.cpp']) - - # Pass multiple files. - (files, options) = parse(['--output=emacs', 'foo.cpp', 'bar.cpp']) - self.assertEquals(files, ['foo.cpp', 'bar.cpp']) + def test_check_webkit_style_parser(self): + # Exercise the code path to make sure the function does not error out. + parser = check_webkit_style_parser() class ProcessorDispatcherSkipTest(unittest.TestCase): @@ -519,30 +314,96 @@ class ProcessorDispatcherDispatchTest(unittest.TestCase): self.assert_processor_none(path) -class StyleCheckerTest(unittest.TestCase): +class StyleCheckerConfigurationTest(unittest.TestCase): - """Test the StyleChecker class. + """Tests the StyleCheckerConfiguration class.""" - Attributes: - error_messages: A string containing all of the warning messages - written to the mock_stderr_write method of - this class. + def setUp(self): + self._error_messages = [] + """The messages written to _mock_stderr_write() of this class.""" - """ + def _mock_stderr_write(self, message): + self._error_messages.append(message) + + def _style_checker_configuration(self, output_format="vs7"): + """Return a StyleCheckerConfiguration instance for testing.""" + base_rules = ["-whitespace", "+whitespace/tab"] + filter_configuration = FilterConfiguration(base_rules=base_rules) + + return StyleCheckerConfiguration( + filter_configuration=filter_configuration, + max_reports_per_category={"whitespace/newline": 1}, + output_format=output_format, + stderr_write=self._mock_stderr_write, + verbosity=3) + + def test_init(self): + """Test the __init__() method.""" + configuration = self._style_checker_configuration() + + # Check that __init__ sets the "public" data attributes correctly. + self.assertEquals(configuration.max_reports_per_category, + {"whitespace/newline": 1}) + self.assertEquals(configuration.stderr_write, self._mock_stderr_write) + self.assertEquals(configuration.verbosity, 3) + + def test_is_reportable(self): + """Test the is_reportable() method.""" + config = self._style_checker_configuration() + + self.assertTrue(config.is_reportable("whitespace/tab", 3, "foo.txt")) + + # Test the confidence check code path by varying the confidence. + self.assertFalse(config.is_reportable("whitespace/tab", 2, "foo.txt")) + + # Test the category check code path by varying the category. + self.assertFalse(config.is_reportable("whitespace/line", 4, "foo.txt")) + + def _call_write_style_error(self, output_format): + config = self._style_checker_configuration(output_format=output_format) + config.write_style_error(category="whitespace/tab", + confidence=5, + file_path="foo.h", + line_number=100, + message="message") + + def test_write_style_error_emacs(self): + """Test the write_style_error() method.""" + self._call_write_style_error("emacs") + self.assertEquals(self._error_messages, + ["foo.h:100: message [whitespace/tab] [5]\n"]) + + def test_write_style_error_vs7(self): + """Test the write_style_error() method.""" + self._call_write_style_error("vs7") + self.assertEquals(self._error_messages, + ["foo.h(100): message [whitespace/tab] [5]\n"]) + + +class StyleCheckerTest(unittest.TestCase): + + """Test the StyleChecker class.""" def _mock_stderr_write(self, message): pass - def _style_checker(self, options): - return StyleChecker(options, self._mock_stderr_write) + def _style_checker(self, configuration): + return StyleChecker(configuration) def test_init(self): """Test __init__ constructor.""" - options = ProcessorOptions() - style_checker = self._style_checker(options) + configuration = StyleCheckerConfiguration( + filter_configuration=FilterConfiguration(), + max_reports_per_category={}, + output_format="vs7", + stderr_write=self._mock_stderr_write, + verbosity=3) + + style_checker = self._style_checker(configuration) + self.assertEquals(style_checker._configuration, configuration) self.assertEquals(style_checker.error_count, 0) - self.assertEquals(style_checker.options, options) + self.assertEquals(style_checker.file_count, 0) class StyleCheckerCheckFileTest(unittest.TestCase): @@ -609,20 +470,21 @@ class StyleCheckerCheckFileTest(unittest.TestCase): # Confirm that the attributes are reset. self.assert_attributes(None, None, None, "") - # Create a test StyleChecker instance. - # - # The verbosity attribute is the only ProcessorOptions - # attribute that needs to be checked in this test. - # This is because it is the only option is directly - # passed to the constructor of a style processor. - options = ProcessorOptions(verbosity=3) + configuration = StyleCheckerConfiguration( + filter_configuration=FilterConfiguration(), + max_reports_per_category={"whitespace/newline": 1}, + output_format="vs7", + stderr_write=self.mock_stderr_write, + verbosity=3) - style_checker = StyleChecker(options, self.mock_stderr_write) + style_checker = StyleChecker(configuration) style_checker.check_file(file_path, self.mock_handle_style_error, self.mock_process_file) + self.assertEquals(1, style_checker.file_count) + def test_check_file_on_skip_without_warning(self): """Test check_file() for a skipped-without-warning file.""" @@ -678,4 +540,3 @@ if __name__ == '__main__': import sys unittest.main() - diff --git a/WebKitTools/Scripts/webkitpy/style/error_handlers.py b/WebKitTools/Scripts/webkitpy/style/error_handlers.py index 1940e03..6bc3f15 100644 --- a/WebKitTools/Scripts/webkitpy/style/error_handlers.py +++ b/WebKitTools/Scripts/webkitpy/style/error_handlers.py @@ -56,30 +56,21 @@ class DefaultStyleErrorHandler(object): """The default style error handler.""" - def __init__(self, file_path, options, increment_error_count, - stderr_write=None): + def __init__(self, file_path, configuration, increment_error_count): """Create a default style error handler. Args: file_path: The path to the file containing the error. This is used for reporting to the user. - options: A ProcessorOptions instance. + configuration: A StyleCheckerConfiguration instance. increment_error_count: A function that takes no arguments and increments the total count of reportable errors. - stderr_write: A function that takes a string as a parameter - and that is called when a style error occurs. - Defaults to sys.stderr.write. This should be - used only for unit tests. """ - if stderr_write is None: - stderr_write = sys.stderr.write - self._file_path = file_path + self._configuration = configuration self._increment_error_count = increment_error_count - self._options = options - self._stderr_write = stderr_write # A string to integer dictionary cache of the number of reportable # errors per category passed to this instance. @@ -99,9 +90,9 @@ class DefaultStyleErrorHandler(object): def _max_reports(self, category): """Return the maximum number of errors to report.""" - if not category in self._options.max_reports_per_category: + if not category in self._configuration.max_reports_per_category: return None - return self._options.max_reports_per_category[category] + return self._configuration.max_reports_per_category[category] def __call__(self, line_number, category, confidence, message): """Handle the occurrence of a style error. @@ -109,9 +100,9 @@ class DefaultStyleErrorHandler(object): See the docstring of this module for more information. """ - if not self._options.is_reportable(category, - confidence, - self._file_path): + if not self._configuration.is_reportable(category=category, + confidence_in_error=confidence, + file_path=self._file_path): return category_total = self._add_reportable_error(category) @@ -122,28 +113,22 @@ class DefaultStyleErrorHandler(object): # Then suppress displaying the error. return - if self._options.output_format == 'vs7': - format_string = "%s(%s): %s [%s] [%d]\n" - else: - format_string = "%s:%s: %s [%s] [%d]\n" + self._configuration.write_style_error(category=category, + confidence=confidence, + file_path=self._file_path, + line_number=line_number, + message=message) if category_total == max_reports: - format_string += ("Suppressing further [%s] reports for this " - "file.\n" % category) - - self._stderr_write(format_string % (self._file_path, - line_number, - message, - category, - confidence)) + self._configuration.stderr_write("Suppressing further [%s] reports " + "for this file.\n" % category) class PatchStyleErrorHandler(object): """The style error function for patch files.""" - def __init__(self, diff, file_path, options, increment_error_count, - stderr_write): + def __init__(self, diff, file_path, configuration, increment_error_count): """Create a patch style error handler for the given path. Args: @@ -153,10 +138,12 @@ class PatchStyleErrorHandler(object): """ self._diff = diff - self._default_error_handler = DefaultStyleErrorHandler(file_path, - options, - increment_error_count, - stderr_write) + + self._default_error_handler = DefaultStyleErrorHandler( + configuration=configuration, + file_path=file_path, + increment_error_count= + increment_error_count) # The line numbers of the modified lines. This is set lazily. self._line_numbers = set() diff --git a/WebKitTools/Scripts/webkitpy/style/error_handlers_unittest.py b/WebKitTools/Scripts/webkitpy/style/error_handlers_unittest.py index 1d7e998..a39ba2a 100644 --- a/WebKitTools/Scripts/webkitpy/style/error_handlers_unittest.py +++ b/WebKitTools/Scripts/webkitpy/style/error_handlers_unittest.py @@ -26,124 +26,111 @@ import unittest from .. style_references import parse_patch -from checker import ProcessorOptions +from checker import StyleCheckerConfiguration from error_handlers import DefaultStyleErrorHandler from error_handlers import PatchStyleErrorHandler - +from filter import FilterConfiguration class StyleErrorHandlerTestBase(unittest.TestCase): def setUp(self): - self._error_messages = "" + self._error_messages = [] self._error_count = 0 def _mock_increment_error_count(self): self._error_count += 1 def _mock_stderr_write(self, message): - self._error_messages += message + self._error_messages.append(message) + + def _style_checker_configuration(self): + """Return a StyleCheckerConfiguration instance for testing.""" + base_rules = ["-whitespace", "+whitespace/tab"] + filter_configuration = FilterConfiguration(base_rules=base_rules) + + return StyleCheckerConfiguration( + filter_configuration=filter_configuration, + max_reports_per_category={"whitespace/tab": 2}, + output_format="vs7", + stderr_write=self._mock_stderr_write, + verbosity=3) class DefaultStyleErrorHandlerTest(StyleErrorHandlerTestBase): """Tests DefaultStyleErrorHandler class.""" - _file_path = "foo.h" - _category = "whitespace/tab" + """The category name for the tests in this class.""" - def _error_handler(self, options): - return DefaultStyleErrorHandler(self._file_path, - options, - self._mock_increment_error_count, - self._mock_stderr_write) + _file_path = "foo.h" + """The file path for the tests in this class.""" def _check_initialized(self): """Check that count and error messages are initialized.""" self.assertEquals(0, self._error_count) - self.assertEquals("", self._error_messages) - - def _call(self, handle_error, options, confidence): - """Handle an error with the given error handler.""" - line_number = 100 - message = "message" - - handle_error(line_number, self._category, confidence, message) - - def _call_error_handler(self, options, confidence): - """Handle an error using a new error handler.""" - handle_error = self._error_handler(options) - self._call(handle_error, options, confidence) - - def test_call_non_reportable(self): - """Test __call__() method with a non-reportable error.""" - confidence = 1 - options = ProcessorOptions(verbosity=3) + self.assertEquals(0, len(self._error_messages)) + + def _error_handler(self, configuration): + return DefaultStyleErrorHandler(configuration=configuration, + file_path=self._file_path, + increment_error_count=self._mock_increment_error_count) + + def _call_error_handler(self, handle_error, confidence): + """Call the given error handler with a test error.""" + handle_error(line_number=100, + category=self._category, + confidence=confidence, + message="message") + + def test_non_reportable_error(self): + """Test __call__() with a non-reportable error.""" self._check_initialized() + configuration = self._style_checker_configuration() + confidence = 1 # Confirm the error is not reportable. - self.assertFalse(options.is_reportable(self._category, - confidence, - self._file_path)) - - self._call_error_handler(options, confidence) + self.assertFalse(configuration.is_reportable(self._category, + confidence, + self._file_path)) + error_handler = self._error_handler(configuration) + self._call_error_handler(error_handler, confidence) self.assertEquals(0, self._error_count) - self.assertEquals("", self._error_messages) - - def test_call_reportable_emacs(self): - """Test __call__() method with a reportable error and emacs format.""" - confidence = 5 - options = ProcessorOptions(verbosity=3, output_format="emacs") - self._check_initialized() + self.assertEquals([], self._error_messages) - self._call_error_handler(options, confidence) - - self.assertEquals(1, self._error_count) - self.assertEquals(self._error_messages, - "foo.h:100: message [whitespace/tab] [5]\n") - - def test_call_reportable_vs7(self): - """Test __call__() method with a reportable error and vs7 format.""" - confidence = 5 - options = ProcessorOptions(verbosity=3, output_format="vs7") + # Also serves as a reportable error test. + def test_max_reports_per_category(self): + """Test error report suppression in __call__() method.""" self._check_initialized() + configuration = self._style_checker_configuration() + error_handler = self._error_handler(configuration) - self._call_error_handler(options, confidence) - - self.assertEquals(1, self._error_count) - self.assertEquals(self._error_messages, - "foo.h(100): message [whitespace/tab] [5]\n") - - def test_call_max_reports_per_category(self): - """Test error report suppression in __call__() method.""" confidence = 5 - options = ProcessorOptions(verbosity=3, - max_reports_per_category={self._category: 2}) - error_handler = self._error_handler(options) - - self._check_initialized() # First call: usual reporting. - self._call(error_handler, options, confidence) + self._call_error_handler(error_handler, confidence) self.assertEquals(1, self._error_count) + self.assertEquals(1, len(self._error_messages)) self.assertEquals(self._error_messages, - "foo.h:100: message [whitespace/tab] [5]\n") + ["foo.h(100): message [whitespace/tab] [5]\n"]) # Second call: suppression message reported. - self._error_messages = "" - self._call(error_handler, options, confidence) + self._call_error_handler(error_handler, confidence) + # The "Suppressing further..." message counts as an additional + # message (but not as an addition to the error count). self.assertEquals(2, self._error_count) - self.assertEquals(self._error_messages, - "foo.h:100: message [whitespace/tab] [5]\n" - "Suppressing further [%s] reports for this file.\n" - % self._category) + self.assertEquals(3, len(self._error_messages)) + self.assertEquals(self._error_messages[-2], + "foo.h(100): message [whitespace/tab] [5]\n") + self.assertEquals(self._error_messages[-1], + "Suppressing further [whitespace/tab] reports " + "for this file.\n") # Third call: no report. - self._error_messages = "" - self._call(error_handler, options, confidence) + self._call_error_handler(error_handler, confidence) self.assertEquals(3, self._error_count) - self.assertEquals(self._error_messages, "") + self.assertEquals(3, len(self._error_messages)) class PatchStyleErrorHandlerTest(StyleErrorHandlerTestBase): @@ -166,22 +153,22 @@ index ef65bee..e3db70e 100644 patch_files = parse_patch(self._patch_string) diff = patch_files[self._file_path] - options = ProcessorOptions(verbosity=3) + configuration = self._style_checker_configuration() - handle_error = PatchStyleErrorHandler(diff, - self._file_path, - options, - self._mock_increment_error_count, - self._mock_stderr_write) + handle_error = PatchStyleErrorHandler(diff=diff, + file_path=self._file_path, + configuration=configuration, + increment_error_count= + self._mock_increment_error_count) category = "whitespace/tab" confidence = 5 message = "message" # Confirm error is reportable. - self.assertTrue(options.is_reportable(category, - confidence, - self._file_path)) + self.assertTrue(configuration.is_reportable(category, + confidence, + self._file_path)) # Confirm error count initialized to zero. self.assertEquals(0, self._error_count) diff --git a/WebKitTools/Scripts/webkitpy/style/filter.py b/WebKitTools/Scripts/webkitpy/style/filter.py index 19c2f4d..608a9e6 100644 --- a/WebKitTools/Scripts/webkitpy/style/filter.py +++ b/WebKitTools/Scripts/webkitpy/style/filter.py @@ -139,12 +139,8 @@ class FilterConfiguration(object): are appended. The first substring match takes precedence, i.e. only the first match triggers an append. - The "path_rules" value is the tuple of filter + The "path_rules" value is a list of filter rules that can be appended to the base rules. - The value is a tuple rather than a list so it - can be used as a dictionary key. The dictionary - is for caching purposes in the implementation of - this class. user_rules: A list of filter rules that is always appended to the base rules and any path rules. In other @@ -165,11 +161,7 @@ class FilterConfiguration(object): self._path_specific_lower = None """The backing store for self._get_path_specific_lower().""" - # FIXME: Make user rules internal after the FilterConfiguration - # attribute is removed from ProcessorOptions (since at - # that point ArgumentPrinter will no longer need to - # access FilterConfiguration.user_rules). - self.user_rules = user_rules + self._user_rules = user_rules self._path_rules_to_filter = {} """Cached dictionary of path rules to CategoryFilter instance.""" @@ -188,7 +180,7 @@ class FilterConfiguration(object): return False if self._path_specific != other._path_specific: return False - if self.user_rules != other.user_rules: + if self._user_rules != other._user_rules: return False return True @@ -210,22 +202,34 @@ class FilterConfiguration(object): return self._path_specific_lower def _path_rules_from_path(self, path): - """Determine the path-specific rules to use, and return as a tuple.""" + """Determine the path-specific rules to use, and return as a tuple. + + This method returns a tuple rather than a list so the return + value can be passed to _filter_from_path_rules() without change. + + """ path = path.lower() for (sub_paths, path_rules) in self._get_path_specific_lower(): for sub_path in sub_paths: if path.find(sub_path) > -1: - return path_rules + return tuple(path_rules) return () # Default to the empty tuple. def _filter_from_path_rules(self, path_rules): - """Return the CategoryFilter associated to a path rules tuple.""" + """Return the CategoryFilter associated to the given path rules. + + Args: + path_rules: A tuple of path rules. We require a tuple rather + than a list so the value can be used as a dictionary + key in self._path_rules_to_filter. + + """ # We reuse the same CategoryFilter where possible to take # advantage of the caching they do. if path_rules not in self._path_rules_to_filter: rules = list(self._base_rules) # Make a copy rules.extend(path_rules) - rules.extend(self.user_rules) + rules.extend(self._user_rules) self._path_rules_to_filter[path_rules] = _CategoryFilter(rules) return self._path_rules_to_filter[path_rules] diff --git a/WebKitTools/Scripts/webkitpy/style/filter_unittest.py b/WebKitTools/Scripts/webkitpy/style/filter_unittest.py index 84760a5..7b8a5402 100644 --- a/WebKitTools/Scripts/webkitpy/style/filter_unittest.py +++ b/WebKitTools/Scripts/webkitpy/style/filter_unittest.py @@ -157,14 +157,14 @@ class FilterConfigurationTest(unittest.TestCase): # Test that the attributes are getting set correctly. # We use parameter values that are different from the defaults. base_rules = ["-"] - path_specific = [(["path"], ("+a",))] + path_specific = [(["path"], ["+a"])] user_rules = ["+"] config = self._config(base_rules, path_specific, user_rules) self.assertEquals(base_rules, config._base_rules) self.assertEquals(path_specific, config._path_specific) - self.assertEquals(user_rules, config.user_rules) + self.assertEquals(user_rules, config._user_rules) def test_default_arguments(self): # Test that the attributes are getting set correctly to the defaults. @@ -172,7 +172,7 @@ class FilterConfigurationTest(unittest.TestCase): self.assertEquals([], config._base_rules) self.assertEquals([], config._path_specific) - self.assertEquals([], config.user_rules) + self.assertEquals([], config._user_rules) def test_eq(self): """Test __eq__ method.""" @@ -185,7 +185,7 @@ class FilterConfigurationTest(unittest.TestCase): # These parameter values are different from the defaults. base_rules = ["-"] - path_specific = [(["path"], ("+a",))] + path_specific = [(["path"], ["+a"])] user_rules = ["+"] self.assertFalse(config.__eq__(FilterConfiguration( @@ -219,8 +219,8 @@ class FilterConfigurationTest(unittest.TestCase): def test_path_specific(self): """Test effect of path_rules_specifier on should_check().""" base_rules = ["-"] - path_specific = [(["path1"], ("+b",)), - (["path2"], ("+c",))] + path_specific = [(["path1"], ["+b"]), + (["path2"], ["+c"])] user_rules = [] config = self._config(base_rules, path_specific, user_rules) @@ -233,7 +233,7 @@ class FilterConfigurationTest(unittest.TestCase): def test_path_with_different_case(self): """Test a path that differs only in case.""" base_rules = ["-"] - path_specific = [(["Foo/"], ("+whitespace",))] + path_specific = [(["Foo/"], ["+whitespace"])] user_rules = [] config = self._config(base_rules, path_specific, user_rules) diff --git a/WebKitTools/Scripts/webkitpy/style/optparser.py b/WebKitTools/Scripts/webkitpy/style/optparser.py new file mode 100644 index 0000000..4137c8b --- /dev/null +++ b/WebKitTools/Scripts/webkitpy/style/optparser.py @@ -0,0 +1,424 @@ +# Copyright (C) 2010 Chris Jerdonek (cjerdonek@webkit.org) +# +# 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. + +"""Supports the parsing of command-line options for check-webkit-style.""" + +import getopt +import os.path +import sys + +from filter import validate_filter_rules +# This module should not import anything from checker.py. + + +def _create_usage(default_options): + """Return the usage string to display for command help. + + Args: + default_options: A DefaultCommandOptionValues instance. + + """ + usage = """ +Syntax: %(program_name)s [--verbose=#] [--git-commit=<SingleCommit>] [--output=vs7] + [--filter=-x,+y,...] [file] ... + + The style guidelines this tries to follow are here: + http://webkit.org/coding/coding-style.html + + Every style error is given a confidence score from 1-5, with 5 meaning + we are certain of the problem, and 1 meaning it could be a legitimate + construct. This can miss some errors and does not substitute for + code review. + + To prevent specific lines from being linted, add a '// NOLINT' comment to the + end of the line. + + Linted extensions are .cpp, .c and .h. Other file types are ignored. + + The file parameter is optional and accepts multiple files. Leaving + out the file parameter applies the check to all files considered changed + by your source control management system. + + Flags: + + verbose=# + A number 1-5 that restricts output to errors with a confidence + score at or above this value. In particular, the value 1 displays + all errors. The default is %(default_verbosity)s. + + git-commit=<SingleCommit> + Checks the style of everything from the given commit to the local tree. + + output=vs7 + The output format, which may be one of + emacs : to ease emacs parsing + vs7 : compatible with Visual Studio + Defaults to "%(default_output_format)s". Other formats are unsupported. + + filter=-x,+y,... + A comma-separated list of boolean filter rules used to filter + which categories of style guidelines to check. The script checks + a category if the category passes the filter rules, as follows. + + Any webkit category starts out passing. All filter rules are then + evaluated left to right, with later rules taking precedence. For + example, the rule "+foo" passes any category that starts with "foo", + and "-foo" fails any such category. The filter input "-whitespace, + +whitespace/braces" fails the category "whitespace/tab" and passes + "whitespace/braces". + + Examples: --filter=-whitespace,+whitespace/braces + --filter=-whitespace,-runtime/printf,+runtime/printf_format + --filter=-,+build/include_what_you_use + + Category names appear in error messages in brackets, for example + [whitespace/indent]. To see a list of all categories available to + %(program_name)s, along with which are enabled by default, pass + the empty filter as follows: + --filter= +""" % {'program_name': os.path.basename(sys.argv[0]), + 'default_verbosity': default_options.verbosity, + 'default_output_format': default_options.output_format} + + return usage + + +# This class should not have knowledge of the flag key names. +class DefaultCommandOptionValues(object): + + """Stores the default check-webkit-style command-line options. + + Attributes: + output_format: A string that is the default output format. + verbosity: An integer that is the default verbosity level. + + """ + + def __init__(self, output_format, verbosity): + self.output_format = output_format + self.verbosity = verbosity + + +# FIXME: Eliminate support for "extra_flag_values". +# +# This class should not have knowledge of the flag key names. +class CommandOptionValues(object): + + """Stores the option values passed by the user via the command line. + + Attributes: + extra_flag_values: A string-string dictionary of all flag key-value + pairs that are not otherwise represented by this + class. The default is the empty dictionary. + + filter_rules: The list of filter rules provided by the user. + These rules are appended to the base rules and + path-specific rules and so take precedence over + the base filter rules, etc. + + git_commit: A string representing the git commit to check. + The default is None. + + output_format: A string that is the output format. The supported + output formats are "emacs" which emacs can parse + and "vs7" which Microsoft Visual Studio 7 can parse. + + verbosity: An integer between 1-5 inclusive that restricts output + to errors with a confidence score at or above this value. + The default is 1, which reports all errors. + + """ + def __init__(self, + extra_flag_values=None, + filter_rules=None, + git_commit=None, + output_format="emacs", + verbosity=1): + if extra_flag_values is None: + extra_flag_values = {} + if filter_rules is None: + filter_rules = [] + + if output_format not in ("emacs", "vs7"): + raise ValueError('Invalid "output_format" parameter: ' + 'value must be "emacs" or "vs7". ' + 'Value given: "%s".' % output_format) + + if (verbosity < 1) or (verbosity > 5): + raise ValueError('Invalid "verbosity" parameter: ' + "value must be an integer between 1-5 inclusive. " + 'Value given: "%s".' % verbosity) + + self.extra_flag_values = extra_flag_values + self.filter_rules = filter_rules + self.git_commit = git_commit + self.output_format = output_format + self.verbosity = verbosity + + # Useful for unit testing. + def __eq__(self, other): + """Return whether this instance is equal to another.""" + if self.extra_flag_values != other.extra_flag_values: + return False + if self.filter_rules != other.filter_rules: + return False + if self.git_commit != other.git_commit: + return False + if self.output_format != other.output_format: + return False + if self.verbosity != other.verbosity: + return False + + return True + + # Useful for unit testing. + def __ne__(self, other): + # Python does not automatically deduce this from __eq__(). + return not self.__eq__(other) + + +class ArgumentPrinter(object): + + """Supports the printing of check-webkit-style command arguments.""" + + def _flag_pair_to_string(self, flag_key, flag_value): + return '--%(key)s=%(val)s' % {'key': flag_key, 'val': flag_value } + + def to_flag_string(self, options): + """Return a flag string of the given CommandOptionValues instance. + + This method orders the flag values alphabetically by the flag key. + + Args: + options: A CommandOptionValues instance. + + """ + flags = options.extra_flag_values.copy() + + flags['output'] = options.output_format + flags['verbose'] = options.verbosity + # Only include the filter flag if user-provided rules are present. + filter_rules = options.filter_rules + if filter_rules: + flags['filter'] = ",".join(filter_rules) + if options.git_commit: + flags['git-commit'] = options.git_commit + + flag_string = '' + # Alphabetizing lets us unit test this method. + for key in sorted(flags.keys()): + flag_string += self._flag_pair_to_string(key, flags[key]) + ' ' + + return flag_string.strip() + + +# FIXME: Replace the use of getopt.getopt() with optparse.OptionParser. +class ArgumentParser(object): + + # FIXME: Move the documentation of the attributes to the __init__ + # docstring after making the attributes internal. + """Supports the parsing of check-webkit-style command arguments. + + Attributes: + create_usage: A function that accepts a DefaultCommandOptionValues + instance and returns a string of usage instructions. + Defaults to the function that generates the usage + string for check-webkit-style. + default_options: A DefaultCommandOptionValues instance that provides + the default values for options not explicitly + provided by the user. + stderr_write: A function that takes a string as a parameter and + serves as stderr.write. Defaults to sys.stderr.write. + This parameter should be specified only for unit tests. + + """ + + def __init__(self, + all_categories, + default_options, + base_filter_rules=None, + create_usage=None, + stderr_write=None): + """Create an ArgumentParser instance. + + Args: + all_categories: The set of all available style categories. + default_options: See the corresponding attribute in the class + docstring. + Keyword Args: + base_filter_rules: The list of filter rules at the beginning of + the list of rules used to check style. This + list has the least precedence when checking + style and precedes any user-provided rules. + The class uses this parameter only for display + purposes to the user. Defaults to the empty list. + create_usage: See the documentation of the corresponding + attribute in the class docstring. + stderr_write: See the documentation of the corresponding + attribute in the class docstring. + + """ + if base_filter_rules is None: + base_filter_rules = [] + if create_usage is None: + create_usage = _create_usage + if stderr_write is None: + stderr_write = sys.stderr.write + + self._all_categories = all_categories + self._base_filter_rules = base_filter_rules + # FIXME: Rename these to reflect that they are internal. + self.create_usage = create_usage + self.default_options = default_options + self.stderr_write = stderr_write + + def _exit_with_usage(self, error_message=''): + """Exit and print a usage string with an optional error message. + + Args: + error_message: A string that is an error message to print. + + """ + usage = self.create_usage(self.default_options) + self.stderr_write(usage) + if error_message: + sys.exit('\nFATAL ERROR: ' + error_message) + else: + sys.exit(1) + + def _exit_with_categories(self): + """Exit and print the style categories and default filter rules.""" + self.stderr_write('\nAll categories:\n') + for category in sorted(self._all_categories): + self.stderr_write(' ' + category + '\n') + + self.stderr_write('\nDefault filter rules**:\n') + for filter_rule in sorted(self._base_filter_rules): + self.stderr_write(' ' + filter_rule + '\n') + self.stderr_write('\n**The command always evaluates the above rules, ' + 'and before any --filter flag.\n\n') + + sys.exit(0) + + def _parse_filter_flag(self, flag_value): + """Parse the --filter flag, and return a list of filter rules. + + Args: + flag_value: A string of comma-separated filter rules, for + example "-whitespace,+whitespace/indent". + + """ + filters = [] + for uncleaned_filter in flag_value.split(','): + filter = uncleaned_filter.strip() + if not filter: + continue + filters.append(filter) + return filters + + def parse(self, args, extra_flags=None): + """Parse the command line arguments to check-webkit-style. + + Args: + args: A list of command-line arguments as returned by sys.argv[1:]. + extra_flags: A list of flags whose values we want to extract, but + are not supported by the CommandOptionValues class. + An example flag "new_flag=". This defaults to the + empty list. + + Returns: + A tuple of (filenames, options) + + filenames: The list of filenames to check. + options: A CommandOptionValues instance. + + """ + if extra_flags is None: + extra_flags = [] + + output_format = self.default_options.output_format + verbosity = self.default_options.verbosity + + # The flags already supported by the CommandOptionValues class. + flags = ['help', 'output=', 'verbose=', 'filter=', 'git-commit='] + + for extra_flag in extra_flags: + if extra_flag in flags: + raise ValueError('Flag \'%(extra_flag)s is duplicated ' + 'or already supported.' % + {'extra_flag': extra_flag}) + flags.append(extra_flag) + + try: + (opts, filenames) = getopt.getopt(args, '', flags) + except getopt.GetoptError: + # FIXME: Settle on an error handling approach: come up + # with a consistent guideline as to when and whether + # a ValueError should be raised versus calling + # sys.exit when needing to interrupt execution. + self._exit_with_usage('Invalid arguments.') + + extra_flag_values = {} + git_commit = None + filter_rules = [] + + for (opt, val) in opts: + if opt == '--help': + self._exit_with_usage() + elif opt == '--output': + output_format = val + elif opt == '--verbose': + verbosity = val + elif opt == '--git-commit': + git_commit = val + elif opt == '--filter': + if not val: + self._exit_with_categories() + filter_rules = self._parse_filter_flag(val) + else: + extra_flag_values[opt] = val + + # Check validity of resulting values. + if filenames and (git_commit != None): + self._exit_with_usage('It is not possible to check files and a ' + 'specific commit at the same time.') + + if output_format not in ('emacs', 'vs7'): + raise ValueError('Invalid --output value "%s": The only ' + 'allowed output formats are emacs and vs7.' % + output_format) + + validate_filter_rules(filter_rules, self._all_categories) + + verbosity = int(verbosity) + if (verbosity < 1) or (verbosity > 5): + raise ValueError('Invalid --verbose value %s: value must ' + 'be between 1-5.' % verbosity) + + options = CommandOptionValues(extra_flag_values=extra_flag_values, + filter_rules=filter_rules, + git_commit=git_commit, + output_format=output_format, + verbosity=verbosity) + + return (filenames, options) + diff --git a/WebKitTools/Scripts/webkitpy/style/optparser_unittest.py b/WebKitTools/Scripts/webkitpy/style/optparser_unittest.py new file mode 100644 index 0000000..f23c5d1 --- /dev/null +++ b/WebKitTools/Scripts/webkitpy/style/optparser_unittest.py @@ -0,0 +1,258 @@ +# Copyright (C) 2010 Chris Jerdonek (cjerdonek@webkit.org) +# +# 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. + +"""Unit tests for parser.py.""" + +import unittest + +from optparser import _create_usage +from optparser import ArgumentParser +from optparser import ArgumentPrinter +from optparser import CommandOptionValues as ProcessorOptions +from optparser import DefaultCommandOptionValues + + +class CreateUsageTest(unittest.TestCase): + + """Tests the _create_usage() function.""" + + def test_create_usage(self): + default_options = DefaultCommandOptionValues(output_format="vs7", + verbosity=3) + # Exercise the code path to make sure the function does not error out. + _create_usage(default_options) + + +class ArgumentPrinterTest(unittest.TestCase): + + """Tests the ArgumentPrinter class.""" + + _printer = ArgumentPrinter() + + def _create_options(self, + output_format='emacs', + verbosity=3, + filter_rules=[], + git_commit=None, + extra_flag_values={}): + return ProcessorOptions(extra_flag_values=extra_flag_values, + filter_rules=filter_rules, + git_commit=git_commit, + output_format=output_format, + verbosity=verbosity) + + def test_to_flag_string(self): + options = self._create_options('vs7', 5, ['+foo', '-bar'], 'git', + {'a': 0, 'z': 1}) + self.assertEquals('--a=0 --filter=+foo,-bar --git-commit=git ' + '--output=vs7 --verbose=5 --z=1', + self._printer.to_flag_string(options)) + + # This is to check that --filter and --git-commit do not + # show up when not user-specified. + options = self._create_options() + self.assertEquals('--output=emacs --verbose=3', + self._printer.to_flag_string(options)) + + +class ArgumentParserTest(unittest.TestCase): + + """Test the ArgumentParser class.""" + + def _parse(self): + """Return a default parse() function for testing.""" + return self._create_parser().parse + + def _create_defaults(self): + """Return a DefaultCommandOptionValues instance for testing.""" + base_filter_rules = ["-", "+whitespace"] + return DefaultCommandOptionValues(output_format="vs7", + verbosity=3) + + def _create_parser(self): + """Return an ArgumentParser instance for testing.""" + def stderr_write(message): + # We do not want the usage string or style categories + # to print during unit tests, so print nothing. + return + + default_options = self._create_defaults() + + all_categories = ["build" ,"whitespace"] + return ArgumentParser(all_categories=all_categories, + base_filter_rules=[], + default_options=default_options, + stderr_write=stderr_write) + + def test_parse_documentation(self): + parse = self._parse() + + # FIXME: Test both the printing of the usage string and the + # filter categories help. + + # Request the usage string. + self.assertRaises(SystemExit, parse, ['--help']) + # Request default filter rules and available style categories. + self.assertRaises(SystemExit, parse, ['--filter=']) + + def test_parse_bad_values(self): + parse = self._parse() + + # Pass an unsupported argument. + self.assertRaises(SystemExit, parse, ['--bad']) + + self.assertRaises(ValueError, parse, ['--verbose=bad']) + self.assertRaises(ValueError, parse, ['--verbose=0']) + self.assertRaises(ValueError, parse, ['--verbose=6']) + parse(['--verbose=1']) # works + parse(['--verbose=5']) # works + + self.assertRaises(ValueError, parse, ['--output=bad']) + parse(['--output=vs7']) # works + + # Pass a filter rule not beginning with + or -. + self.assertRaises(ValueError, parse, ['--filter=build']) + parse(['--filter=+build']) # works + # Pass files and git-commit at the same time. + self.assertRaises(SystemExit, parse, ['--git-commit=', 'file.txt']) + # Pass an extra flag already supported. + self.assertRaises(ValueError, parse, [], ['filter=']) + parse([], ['extra=']) # works + # Pass an extra flag with typo. + self.assertRaises(SystemExit, parse, ['--extratypo='], ['extra=']) + parse(['--extra='], ['extra=']) # works + self.assertRaises(ValueError, parse, [], ['extra=', 'extra=']) + + + def test_parse_default_arguments(self): + parse = self._parse() + + (files, options) = parse([]) + + self.assertEquals(files, []) + + self.assertEquals(options.output_format, 'vs7') + self.assertEquals(options.verbosity, 3) + self.assertEquals(options.filter_rules, []) + self.assertEquals(options.git_commit, None) + + def test_parse_explicit_arguments(self): + parse = self._parse() + + # Pass non-default explicit values. + (files, options) = parse(['--output=emacs']) + self.assertEquals(options.output_format, 'emacs') + (files, options) = parse(['--verbose=4']) + self.assertEquals(options.verbosity, 4) + (files, options) = parse(['--git-commit=commit']) + self.assertEquals(options.git_commit, 'commit') + + # Pass user_rules. + (files, options) = parse(['--filter=+build,-whitespace']) + self.assertEquals(options.filter_rules, + ["+build", "-whitespace"]) + + # Pass spurious white space in user rules. + (files, options) = parse(['--filter=+build, -whitespace']) + self.assertEquals(options.filter_rules, + ["+build", "-whitespace"]) + + # Pass extra flag values. + (files, options) = parse(['--extra'], ['extra']) + self.assertEquals(options.extra_flag_values, {'--extra': ''}) + (files, options) = parse(['--extra='], ['extra=']) + self.assertEquals(options.extra_flag_values, {'--extra': ''}) + (files, options) = parse(['--extra=x'], ['extra=']) + self.assertEquals(options.extra_flag_values, {'--extra': 'x'}) + + def test_parse_files(self): + parse = self._parse() + + (files, options) = parse(['foo.cpp']) + self.assertEquals(files, ['foo.cpp']) + + # Pass multiple files. + (files, options) = parse(['--output=emacs', 'foo.cpp', 'bar.cpp']) + self.assertEquals(files, ['foo.cpp', 'bar.cpp']) + + +class CommandOptionValuesTest(unittest.TestCase): + + """Tests CommandOptionValues class.""" + + def test_init(self): + """Test __init__ constructor.""" + # Check default parameters. + options = ProcessorOptions() + self.assertEquals(options.extra_flag_values, {}) + self.assertEquals(options.filter_rules, []) + self.assertEquals(options.git_commit, None) + self.assertEquals(options.output_format, "emacs") + self.assertEquals(options.verbosity, 1) + + # Check argument validation. + self.assertRaises(ValueError, ProcessorOptions, output_format="bad") + ProcessorOptions(output_format="emacs") # No ValueError: works + ProcessorOptions(output_format="vs7") # works + self.assertRaises(ValueError, ProcessorOptions, verbosity=0) + self.assertRaises(ValueError, ProcessorOptions, verbosity=6) + ProcessorOptions(verbosity=1) # works + ProcessorOptions(verbosity=5) # works + + # Check attributes. + options = ProcessorOptions(extra_flag_values={"extra_value" : 2}, + filter_rules=["+"], + git_commit="commit", + output_format="vs7", + verbosity=3) + self.assertEquals(options.extra_flag_values, {"extra_value" : 2}) + self.assertEquals(options.filter_rules, ["+"]) + self.assertEquals(options.git_commit, "commit") + self.assertEquals(options.output_format, "vs7") + self.assertEquals(options.verbosity, 3) + + def test_eq(self): + """Test __eq__ equality function.""" + # == calls __eq__. + self.assertTrue(ProcessorOptions() == ProcessorOptions()) + + # Verify that a difference in any argument causes equality to fail. + options = ProcessorOptions(extra_flag_values={"extra_value" : 1}, + filter_rules=["+"], + git_commit="commit", + output_format="vs7", + verbosity=1) + self.assertFalse(options == ProcessorOptions(extra_flag_values= + {"extra_value" : 2})) + self.assertFalse(options == ProcessorOptions(filter_rules=["-"])) + self.assertFalse(options == ProcessorOptions(git_commit="commit2")) + self.assertFalse(options == ProcessorOptions(output_format="emacs")) + self.assertFalse(options == ProcessorOptions(verbosity=2)) + + def test_ne(self): + """Test __ne__ inequality function.""" + # != calls __ne__. + # By default, __ne__ always returns true on different objects. + # Thus, just check the distinguishing case to verify that the + # code defines __ne__. + self.assertFalse(ProcessorOptions() != ProcessorOptions()) + diff --git a/WebKitTools/Scripts/webkitpy/style/processors/cpp.py b/WebKitTools/Scripts/webkitpy/style/processors/cpp.py index 182c967..f83ae6a 100644 --- a/WebKitTools/Scripts/webkitpy/style/processors/cpp.py +++ b/WebKitTools/Scripts/webkitpy/style/processors/cpp.py @@ -1868,6 +1868,10 @@ def check_for_null(file_extension, clean_lines, line_number, error): if search(r'\bg_object_[sg]et\b', line): return + # Don't warn about NULL usage in g_str{join,concat}(). See Bug 34834 + if search(r'\bg_str(join|concat)\b', line): + return + if search(r'\bNULL\b', line): error(line_number, 'readability/null', 5, 'Use 0 instead of NULL.') return @@ -2421,7 +2425,9 @@ def check_identifier_name_in_declaration(filename, line_number, line, error): # Convert "long long", "long double", and "long long int" to # simple types, but don't remove simple "long". line = sub(r'long (long )?(?=long|double|int)', '', line) - line = sub(r'\b(unsigned|signed|inline|using|static|const|volatile|auto|register|extern|typedef|restrict|struct|class|virtual)(?=\W)', '', line) + # Convert unsigned/signed types to simple types, too. + line = sub(r'(unsigned|signed) (?=char|short|int|long)', '', line) + line = sub(r'\b(inline|using|static|const|volatile|auto|register|extern|typedef|restrict|struct|class|virtual)(?=\W)', '', line) # Remove all template parameters by removing matching < and >. # Loop until no templates are removed to remove nested templates. @@ -2449,8 +2455,9 @@ def check_identifier_name_in_declaration(filename, line_number, line, error): # Detect variable and functions. type_regexp = r'\w([\w]|\s*[*&]\s*|::)+' identifier_regexp = r'(?P<identifier>[\w:]+)' + maybe_bitfield_regexp = r'(:\s*\d+\s*)?' character_after_identifier_regexp = r'(?P<character_after_identifier>[[;()=,])(?!=)' - declaration_without_type_regexp = r'\s*' + identifier_regexp + r'\s*' + character_after_identifier_regexp + declaration_without_type_regexp = r'\s*' + identifier_regexp + r'\s*' + maybe_bitfield_regexp + character_after_identifier_regexp declaration_with_type_regexp = r'\s*' + type_regexp + r'\s' + declaration_without_type_regexp is_function_arguments = False number_of_identifiers = 0 @@ -2982,4 +2989,3 @@ class CppProcessor(object): def process_file_data(filename, file_extension, lines, error, verbosity): processor = CppProcessor(filename, file_extension, error, verbosity) processor.process(lines) - diff --git a/WebKitTools/Scripts/webkitpy/style/processors/cpp_unittest.py b/WebKitTools/Scripts/webkitpy/style/processors/cpp_unittest.py index fb5a487..c786b8e 100644 --- a/WebKitTools/Scripts/webkitpy/style/processors/cpp_unittest.py +++ b/WebKitTools/Scripts/webkitpy/style/processors/cpp_unittest.py @@ -3392,13 +3392,26 @@ class WebKitStyleTest(CppStyleTestBase): '', 'foo.m') - # Make sure that the NULL check does not apply to g_object_{set,get} + # Make sure that the NULL check does not apply to g_object_{set,get} and + # g_str{join,concat} self.assert_lint( 'g_object_get(foo, "prop", &bar, NULL);', '') self.assert_lint( 'g_object_set(foo, "prop", bar, NULL);', '') + self.assert_lint( + 'gchar* result = g_strconcat("part1", "part2", "part3", NULL);', + '') + self.assert_lint( + 'gchar* result = g_strconcat("part1", NULL);', + '') + self.assert_lint( + 'gchar* result = g_strjoin(",", "part1", "part2", "part3", NULL);', + '') + self.assert_lint( + 'gchar* result = g_strjoin(",", "part1", NULL);', + '') # 2. C++ and C bool values should be written as true and # false. Objective-C BOOL values should be written as YES and NO. @@ -3503,6 +3516,12 @@ class WebKitStyleTest(CppStyleTestBase): '_length' + name_error_message) self.assert_lint('short length_;', 'length_' + name_error_message) + self.assert_lint('unsigned _length;', + '_length' + name_error_message) + self.assert_lint('unsigned int _length;', + '_length' + name_error_message) + self.assert_lint('unsigned long long _length;', + '_length' + name_error_message) # Pointers, references, functions, templates, and adjectives. self.assert_lint('char* under_score;', @@ -3599,6 +3618,10 @@ class WebKitStyleTest(CppStyleTestBase): # const_iterator is allowed as well. self.assert_lint('typedef VectorType::const_iterator const_iterator;', '') + # Bitfields. + self.assert_lint('unsigned _fillRule : 1;', + '_fillRule' + name_error_message) + def test_comments(self): # A comment at the beginning of a line is ok. diff --git a/WebKitTools/Scripts/webkitpy/style/unittests.py b/WebKitTools/Scripts/webkitpy/style/unittests.py index f8e3f71..62615ab 100644 --- a/WebKitTools/Scripts/webkitpy/style/unittests.py +++ b/WebKitTools/Scripts/webkitpy/style/unittests.py @@ -38,6 +38,7 @@ import unittest from checker_unittest import * from error_handlers_unittest import * from filter_unittest import * +from optparser_unittest import * from processors.common_unittest import * from processors.cpp_unittest import * from processors.text_unittest import * |