diff options
Diffstat (limited to 'Tools/Scripts/webkitpy/style')
-rw-r--r-- | Tools/Scripts/webkitpy/style/checker.py | 21 | ||||
-rwxr-xr-x | Tools/Scripts/webkitpy/style/checker_unittest.py | 31 | ||||
-rw-r--r-- | Tools/Scripts/webkitpy/style/checkers/changelog.py | 74 | ||||
-rw-r--r-- | Tools/Scripts/webkitpy/style/checkers/changelog_unittest.py | 155 | ||||
-rw-r--r-- | Tools/Scripts/webkitpy/style/error_handlers.py | 10 |
5 files changed, 275 insertions, 16 deletions
diff --git a/Tools/Scripts/webkitpy/style/checker.py b/Tools/Scripts/webkitpy/style/checker.py index 975432b..48abcf9 100644 --- a/Tools/Scripts/webkitpy/style/checker.py +++ b/Tools/Scripts/webkitpy/style/checker.py @@ -36,6 +36,7 @@ import sys from checkers.common import categories as CommonCategories from checkers.common import CarriageReturnChecker +from checkers.changelog import ChangeLogChecker from checkers.cpp import CppChecker from checkers.python import PythonChecker from checkers.test_expectations import TestExpectationsChecker @@ -180,6 +181,7 @@ _PATH_RULES_SPECIFIER = [ # struct members. Also, we allow unnecessary parameter names in # WebKit2 APIs because we're matching CF's header style. "Source/WebKit2/UIProcess/API/C/", + "Source/WebKit2/Shared/API/c/", "Source/WebKit2/WebProcess/InjectedBundle/API/c/"], ["-readability/naming", "-readability/parameter_name", @@ -419,10 +421,11 @@ class FileType: NONE = 0 # FileType.NONE evaluates to False. # Alphabetize remaining types - CPP = 1 - PYTHON = 2 - TEXT = 3 - XML = 4 + CHANGELOG = 1 + CPP = 2 + PYTHON = 3 + TEXT = 4 + XML = 5 class CheckerDispatcher(object): @@ -481,8 +484,9 @@ class CheckerDispatcher(object): return FileType.PYTHON elif file_extension in _XML_FILE_EXTENSIONS: return FileType.XML - elif (os.path.basename(file_path).startswith('ChangeLog') or - (not file_extension and os.path.join("Tools", "Scripts") in file_path) or + elif os.path.basename(file_path).startswith('ChangeLog'): + return FileType.CHANGELOG + elif ((not file_extension and os.path.join("Tools", "Scripts") in file_path) or file_extension in _TEXT_FILE_EXTENSIONS): return FileType.TEXT else: @@ -493,6 +497,11 @@ class CheckerDispatcher(object): """Instantiate and return a style checker based on file type.""" if file_type == FileType.NONE: checker = None + elif file_type == FileType.CHANGELOG: + should_line_be_checked = None + if handle_style_error: + should_line_be_checked = handle_style_error.should_line_be_checked + checker = ChangeLogChecker(file_path, handle_style_error, should_line_be_checked) elif file_type == FileType.CPP: file_extension = self._file_extension(file_path) checker = CppChecker(file_path, file_extension, diff --git a/Tools/Scripts/webkitpy/style/checker_unittest.py b/Tools/Scripts/webkitpy/style/checker_unittest.py index a796e0b..144d40a 100755 --- a/Tools/Scripts/webkitpy/style/checker_unittest.py +++ b/Tools/Scripts/webkitpy/style/checker_unittest.py @@ -52,6 +52,7 @@ from checker import CheckerDispatcher from checker import ProcessorBase from checker import StyleProcessor from checker import StyleProcessorConfiguration +from checkers.changelog import ChangeLogChecker from checkers.cpp import CppChecker from checkers.python import PythonChecker from checkers.text import TextChecker @@ -368,12 +369,10 @@ class CheckerDispatcherDispatchTest(unittest.TestCase): """Tests dispatch() method of CheckerDispatcher class.""" - def mock_handle_style_error(self): - pass - def dispatch(self, file_path): """Call dispatch() with the given file path.""" dispatcher = CheckerDispatcher() + self.mock_handle_style_error = DefaultStyleErrorHandler('', None, None, []) checker = dispatcher.dispatch(file_path, self.mock_handle_style_error, min_confidence=3) @@ -395,6 +394,10 @@ class CheckerDispatcherDispatchTest(unittest.TestCase): "got_class": got_class, "expected_class": expected_class}) + def assert_checker_changelog(self, file_path): + """Assert that the dispatched checker is a ChangeLogChecker.""" + self.assert_checker(file_path, ChangeLogChecker) + def assert_checker_cpp(self, file_path): """Assert that the dispatched checker is a CppChecker.""" self.assert_checker(file_path, CppChecker) @@ -411,6 +414,25 @@ class CheckerDispatcherDispatchTest(unittest.TestCase): """Assert that the dispatched checker is a XMLChecker.""" self.assert_checker(file_path, XMLChecker) + def test_changelog_paths(self): + """Test paths that should be checked as ChangeLog.""" + paths = [ + "ChangeLog", + "ChangeLog-2009-06-16", + os.path.join("Source", "WebCore", "ChangeLog"), + ] + + for path in paths: + self.assert_checker_changelog(path) + + # Check checker attributes on a typical input. + file_path = "ChangeLog" + self.assert_checker_changelog(file_path) + checker = self.dispatch(file_path) + self.assertEquals(checker.file_path, file_path) + self.assertEquals(checker.handle_style_error, + self.mock_handle_style_error) + def test_cpp_paths(self): """Test paths that should be checked as C++.""" paths = [ @@ -465,8 +487,6 @@ class CheckerDispatcherDispatchTest(unittest.TestCase): def test_text_paths(self): """Test paths that should be checked as text.""" paths = [ - "ChangeLog", - "ChangeLog-2009-06-16", "foo.ac", "foo.cc", "foo.cgi", @@ -491,7 +511,6 @@ class CheckerDispatcherDispatchTest(unittest.TestCase): "foo.wm", "foo.xhtml", "foo.y", - os.path.join("Source", "WebCore", "ChangeLog"), os.path.join("Source", "WebCore", "inspector", "front-end", "inspector.js"), os.path.join("Tools", "Scripts", "check-webkit-style"), ] diff --git a/Tools/Scripts/webkitpy/style/checkers/changelog.py b/Tools/Scripts/webkitpy/style/checkers/changelog.py new file mode 100644 index 0000000..75754fa --- /dev/null +++ b/Tools/Scripts/webkitpy/style/checkers/changelog.py @@ -0,0 +1,74 @@ +#!/usr/bin/env python +# +# Copyright (C) 2011 Patrick Gansterer <paroga@paroga.com> +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +"""Checks WebKit style for ChangeLog files.""" + +import re +from common import TabChecker +from webkitpy.common.net.bugzilla import parse_bug_id_from_changelog + + +class ChangeLogChecker(object): + + """Processes text lines for checking style.""" + + def __init__(self, file_path, handle_style_error, should_line_be_checked): + self.file_path = file_path + self.handle_style_error = handle_style_error + self.should_line_be_checked = should_line_be_checked + self._tab_checker = TabChecker(file_path, handle_style_error) + + def check_entry(self, first_line_checked, entry_lines): + if not entry_lines: + return + for line in entry_lines: + if parse_bug_id_from_changelog(line): + break + if re.search("Unreviewed", line, re.IGNORECASE): + break + if re.search("build", line, re.IGNORECASE) and re.search("fix", line, re.IGNORECASE): + break + else: + self.handle_style_error(first_line_checked, + "changelog/bugnumber", 5, + "ChangeLog entry has no bug number") + + def check(self, lines): + self._tab_checker.check(lines) + first_line_checked = 0 + entry_lines = [] + + for line_index, line in enumerate(lines): + if not self.should_line_be_checked(line_index + 1): + # If we transitioned from finding changed lines to + # unchanged lines, then we are done. + if first_line_checked: + break + continue + if not first_line_checked: + first_line_checked = line_index + 1 + entry_lines.append(line) + + self.check_entry(first_line_checked, entry_lines) diff --git a/Tools/Scripts/webkitpy/style/checkers/changelog_unittest.py b/Tools/Scripts/webkitpy/style/checkers/changelog_unittest.py new file mode 100644 index 0000000..02296d3 --- /dev/null +++ b/Tools/Scripts/webkitpy/style/checkers/changelog_unittest.py @@ -0,0 +1,155 @@ +#!/usr/bin/env python +# +# Copyright (C) 2010 Apple Inc. All rights reserved. +# Copyright (C) 2011 Patrick Gansterer <paroga@paroga.com> +# +# 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 test for changelog.py.""" + +import changelog +import unittest + + +class ChangeLogCheckerTest(unittest.TestCase): + """Tests ChangeLogChecker class.""" + + def assert_no_error(self, lines_to_check, changelog_data): + def handle_style_error(line_number, category, confidence, message): + self.fail('Unexpected error: %d %s %d %s for\n%s' % (line_number, category, confidence, message, changelog_data)) + self.lines_to_check = set(lines_to_check) + checker = changelog.ChangeLogChecker('ChangeLog', handle_style_error, self.mock_should_line_be_checked) + checker.check(changelog_data.split('\n')) + + def assert_error(self, expected_line_number, lines_to_check, expected_category, changelog_data): + self.had_error = False + + def handle_style_error(line_number, category, confidence, message): + self.had_error = True + self.assertEquals(expected_line_number, line_number) + self.assertEquals(expected_category, category) + self.lines_to_check = set(lines_to_check) + checker = changelog.ChangeLogChecker('ChangeLog', handle_style_error, self.mock_should_line_be_checked) + checker.check(changelog_data.split('\n')) + self.assertTrue(self.had_error) + + def mock_handle_style_error(self): + pass + + def mock_should_line_be_checked(self, line_number): + return line_number in self.lines_to_check + + def test_init(self): + checker = changelog.ChangeLogChecker('ChangeLog', self.mock_handle_style_error, self.mock_should_line_be_checked) + self.assertEquals(checker.file_path, 'ChangeLog') + self.assertEquals(checker.handle_style_error, self.mock_handle_style_error) + self.assertEquals(checker.should_line_be_checked, self.mock_should_line_be_checked) + + def test_missing_bug_number(self): + self.assert_error(1, range(1, 20), 'changelog/bugnumber', + '2011-01-01 Patrick Gansterer <paroga@paroga.com>\n' + '\n' + ' Example bug\n') + self.assert_error(1, range(1, 20), 'changelog/bugnumber', + '2011-01-01 Patrick Gansterer <paroga@paroga.com>\n' + '\n' + ' Example bug\n' + ' http://bugs.webkit.org/show_bug.cgi?id=\n') + self.assert_error(1, range(1, 20), 'changelog/bugnumber', + '2011-01-01 Patrick Gansterer <paroga@paroga.com>\n' + '\n' + ' Example bug\n' + ' https://bugs.webkit.org/show_bug.cgi?id=\n') + self.assert_error(1, range(1, 20), 'changelog/bugnumber', + '2011-01-01 Patrick Gansterer <paroga@paroga.com>\n' + '\n' + ' Example bug\n' + ' http://webkit.org/b/\n') + self.assert_error(1, range(1, 20), 'changelog/bugnumber', + '2011-01-01 Patrick Gansterer <paroga@paroga.com>\n' + '\n' + ' Example bug' + '\n' + ' http://trac.webkit.org/changeset/12345\n') + self.assert_error(2, range(2, 5), 'changelog/bugnumber', + '2011-01-01 Patrick Gansterer <paroga@paroga.com>\n' + ' Example bug\n' + ' https://bugs.webkit.org/show_bug.cgi\n' + '\n' + '2011-01-01 Patrick Gansterer <paroga@paroga.com>\n' + ' Another change\n') + self.assert_error(2, range(2, 6), 'changelog/bugnumber', + '2011-01-01 Patrick Gansterer <paroga@paroga.com>\n' + ' Example bug\n' + ' More text about bug.\n' + '\n' + '2011-01-01 Patrick Gansterer <paroga@paroga.com>\n' + '\n' + ' No bug in this change.\n') + + def test_no_error(self): + self.assert_no_error([], + '2011-01-01 Patrick Gansterer <paroga@paroga.com>\n' + '\n' + ' Example ChangeLog entry out of range\n' + ' http://example.com/\n') + self.assert_no_error([], + '2011-01-01 Patrick Gansterer <paroga@paroga.com>\n' + '\n' + ' Example bug\n' + ' http://bugs.webkit.org/show_bug.cgi?id=12345\n') + self.assert_no_error(range(1, 20), + '2011-01-01 Patrick Gansterer <paroga@paroga.com>\n' + '\n' + ' Example bug\n' + ' http://bugs.webkit.org/show_bug.cgi?id=12345\n') + self.assert_no_error(range(1, 20), + '2011-01-01 Patrick Gansterer <paroga@paroga.com>\n' + '\n' + ' Example bug\n' + ' https://bugs.webkit.org/show_bug.cgi?id=12345\n') + self.assert_no_error(range(1, 20), + '2011-01-01 Patrick Gansterer <paroga@paroga.com>\n' + '\n' + ' Example bug\n' + ' http://webkit.org/b/12345\n') + self.assert_no_error(range(1, 20), + '2011-01-01 Patrick Gansterer <paroga@paroga.com>\n' + '\n' + ' Unreview build fix for r12345.\n') + self.assert_no_error(range(1, 20), + '2011-01-01 Patrick Gansterer <paroga@paroga.com>\n' + '\n' + ' Fix build after a bad change.\n') + self.assert_no_error(range(1, 20), + '2011-01-01 Patrick Gansterer <paroga@paroga.com>\n' + '\n' + ' Fix example port build.\n') + self.assert_no_error(range(2, 6), + '2011-01-01 Patrick Gansterer <paroga@paroga.com>\n' + ' Example bug\n' + ' https://bugs.webkit.org/show_bug.cgi?id=12345\n' + '\n' + '2011-01-01 Patrick Gansterer <paroga@paroga.com>\n' + ' No bug here!\n') + +if __name__ == '__main__': + unittest.main() diff --git a/Tools/Scripts/webkitpy/style/error_handlers.py b/Tools/Scripts/webkitpy/style/error_handlers.py index 0bede24..5d8b041 100644 --- a/Tools/Scripts/webkitpy/style/error_handlers.py +++ b/Tools/Scripts/webkitpy/style/error_handlers.py @@ -123,16 +123,18 @@ class DefaultStyleErrorHandler(object): return None return self._configuration.max_reports_per_category[category] + def should_line_be_checked(self, line_number): + "Returns if a particular line should be checked" + # Was the line that was modified? + return self._line_numbers is None or line_number in self._line_numbers + def __call__(self, line_number, category, confidence, message): """Handle the occurrence of a style error. See the docstring of this module for more information. """ - if (self._line_numbers is not None and - line_number not in self._line_numbers): - # Then the error occurred in a line that was not modified, so - # the error is not reportable. + if not self.should_line_be_checked(line_number): return if not self._configuration.is_reportable(category=category, |