Changeset 53675 in webkit
- Timestamp:
- Jan 21, 2010 9:39:24 PM (14 years ago)
- Location:
- trunk/WebKitTools
- Files:
-
- 8 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/WebKitTools/ChangeLog
r53667 r53675 1 2010-01-21 Chris Jerdonek <cjerdonek@webkit.org> 2 3 Reviewed by Shinichiro Hamaji. 4 5 Refactored to move file name and file-reading related code 6 from cpp_style.py and text_style.py to checker.py. 7 8 https://bugs.webkit.org/show_bug.cgi?id=33775 9 10 * Scripts/check-webkit-style: 11 - Updates caused by changes to checker.py. 12 13 * Scripts/webkitpy/style/checker.py: 14 - Added SKIPPED_FILES_WITH_WARNING list. 15 - Added SKIPPED_FILES_WITHOUT_WARNING list. 16 - Added FileType class. 17 - Added ProcessorDispatcher class. 18 - In StyleChecker class: 19 - Renamed process_patch() to check_patch(). 20 - Renamed process_file() to check_file(). 21 - Added _process_file(). 22 - Related refactoring. 23 - Addressed check_patch() FIXME to share code with process_file(). 24 25 * Scripts/webkitpy/style/checker_unittest.py: 26 - Added ProcessorDispatcherSkipTest class. 27 - Added ProcessorDispatcherDispatchTest class. 28 - Added StyleCheckerCheckFileTest class. 29 30 * Scripts/webkitpy/style/cpp_style.py: 31 - Renamed process_file_data() to _process_lines. 32 - Removed process_file() (moved logic to checker.py). 33 - Removed can_handle() (moved logic to checker.py). 34 - Added CppProcessor class. 35 - Removed is_exempt() (moved logic to checker.py). 36 - Added process_file_data() back as a wrapper function. 37 38 * Scripts/webkitpy/style/cpp_style_unittest.py: 39 - Removed test_can_handle(). 40 - Removed test_is_exempt(). 41 - Added CppProcessorTest class. 42 43 * Scripts/webkitpy/style/text_style.py: 44 - Added TextProcessor class. 45 - Removed process_file(). 46 - Removed can_handle(). 47 48 * Scripts/webkitpy/style/text_style_unittest.py: 49 - Removed test_can_handle(). 50 - Added TextProcessorTest class. 51 1 52 2010-01-21 Chris Jerdonek <cjerdonek@webkit.org> 2 53 -
trunk/WebKitTools/Scripts/check-webkit-style
r53374 r53675 69 69 if files: 70 70 for filename in files: 71 style_checker. process_file(filename)71 style_checker.check_file(filename) 72 72 73 73 else: … … 85 85 else: 86 86 patch = scm.create_patch() 87 style_checker. process_patch(patch)87 style_checker.check_patch(patch) 88 88 89 89 sys.stderr.write('Total errors found: %d\n' % style_checker.error_count) -
trunk/WebKitTools/Scripts/webkitpy/style/checker.py
r53382 r53675 30 30 """Front end of some style-checker modules.""" 31 31 32 # FIXME: Move more code from cpp_style to here. 33 32 import codecs 34 33 import getopt 35 34 import os.path 36 35 import sys 37 36 38 import cpp_style39 import text_style40 37 from diff_parser import DiffParser 38 from cpp_style import CppProcessor 39 from text_style import TextProcessor 41 40 42 41 … … 159 158 160 159 160 # Some files should be skipped when checking style. For example, 161 # WebKit maintains some files in Mozilla style on purpose to ease 162 # future merges. 163 # 164 # Include a warning for skipped files that are less obvious. 165 SKIPPED_FILES_WITH_WARNING = [ 166 # The Qt API and tests do not follow WebKit style. 167 # They follow Qt style. :) 168 "gtk2drawing.c", # WebCore/platform/gtk/gtk2drawing.c 169 "gtk2drawing.h", # WebCore/platform/gtk/gtk2drawing.h 170 "JavaScriptCore/qt/api/", 171 "WebKit/gtk/tests/", 172 "WebKit/qt/Api/", 173 "WebKit/qt/tests/", 174 ] 175 176 177 # Don't include a warning for skipped files that are more common 178 # and more obvious. 179 SKIPPED_FILES_WITHOUT_WARNING = [ 180 "LayoutTests/" 181 ] 182 183 161 184 def webkit_argument_defaults(): 162 185 """Return the DefaultArguments instance for use by check-webkit-style.""" … … 620 643 621 644 645 # Enum-like idiom 646 class FileType: 647 648 NONE = 1 649 # Alphabetize remaining types 650 CPP = 2 651 TEXT = 3 652 653 654 class ProcessorDispatcher(object): 655 656 """Supports determining whether and how to check style, based on path.""" 657 658 cpp_file_extensions = ( 659 'c', 660 'cpp', 661 'h', 662 ) 663 664 text_file_extensions = ( 665 'css', 666 'html', 667 'idl', 668 'js', 669 'mm', 670 'php', 671 'pm', 672 'py', 673 'txt', 674 ) 675 676 def _file_extension(self, file_path): 677 """Return the file extension without the leading dot.""" 678 return os.path.splitext(file_path)[1].lstrip(".") 679 680 def should_skip_with_warning(self, file_path): 681 """Return whether the given file should be skipped with a warning.""" 682 for skipped_file in SKIPPED_FILES_WITH_WARNING: 683 if file_path.find(skipped_file) >= 0: 684 return True 685 return False 686 687 def should_skip_without_warning(self, file_path): 688 """Return whether the given file should be skipped without a warning.""" 689 for skipped_file in SKIPPED_FILES_WITHOUT_WARNING: 690 if file_path.find(skipped_file) >= 0: 691 return True 692 return False 693 694 def _file_type(self, file_path): 695 """Return the file type corresponding to the given file.""" 696 file_extension = self._file_extension(file_path) 697 698 if (file_extension in self.cpp_file_extensions) or (file_path == '-'): 699 # FIXME: Do something about the comment below and the issue it 700 # raises since cpp_style already relies on the extension. 701 # 702 # Treat stdin as C++. Since the extension is unknown when 703 # reading from stdin, cpp_style tests should not rely on 704 # the extension. 705 return FileType.CPP 706 elif ("ChangeLog" in file_path 707 or "WebKitTools/Scripts/" in file_path 708 or file_extension in self.text_file_extensions): 709 return FileType.TEXT 710 else: 711 return FileType.NONE 712 713 def _create_processor(self, file_type, file_path, handle_style_error, verbosity): 714 """Instantiate and return a style processor based on file type.""" 715 if file_type == FileType.NONE: 716 processor = None 717 elif file_type == FileType.CPP: 718 file_extension = self._file_extension(file_path) 719 processor = CppProcessor(file_path, file_extension, handle_style_error, verbosity) 720 elif file_type == FileType.TEXT: 721 processor = TextProcessor(file_path, handle_style_error) 722 else: 723 raise ValueError('Invalid file type "%(file_type)s": the only valid file types ' 724 "are %(NONE)s, %(CPP)s, and %(TEXT)s." 725 % {"file_type": file_type, 726 "NONE": FileType.NONE, 727 "CPP": FileType.CPP, 728 "TEXT": FileType.TEXT}) 729 730 return processor 731 732 def dispatch_processor(self, file_path, handle_style_error, verbosity): 733 """Instantiate and return a style processor based on file path.""" 734 file_type = self._file_type(file_path) 735 736 processor = self._create_processor(file_type, 737 file_path, 738 handle_style_error, 739 verbosity) 740 return processor 741 742 622 743 class StyleChecker(object): 623 744 … … 633 754 """ 634 755 635 def __init__(self, options, write_error=sys.stderr.write):756 def __init__(self, options, stderr_write=None): 636 757 """Create a StyleChecker instance. 637 758 … … 640 761 stderr_write: A function that takes a string as a parameter 641 762 and that is called when a style error occurs. 642 643 """ 644 self._write_error = write_error 763 Defaults to sys.stderr.write. This should be 764 used only for unit tests. 765 766 """ 767 if stderr_write is None: 768 stderr_write = sys.stderr.write 769 770 self._stderr_write = stderr_write 771 self.error_count = 0 645 772 self.options = options 646 self.error_count = 0 647 648 def _handle_error(self, filename, line_number, category, confidence, message): 773 774 def _handle_style_error(self, filename, line_number, category, confidence, message): 649 775 """Handle the occurrence of a style error while checking. 650 776 … … 676 802 format_string = "%s:%s: %s [%s] [%d]\n" 677 803 678 self._write_error(format_string % (filename, line_number, message, 679 category, confidence)) 680 681 def process_file(self, filename): 682 """Checks style for the specified file. 683 684 If the specified filename is '-', applies cpp_style to the standard input. 685 686 """ 687 if cpp_style.can_handle(filename) or filename == '-': 688 cpp_style.process_file(filename, self._handle_error, self.options.verbosity) 689 elif text_style.can_handle(filename): 690 text_style.process_file(filename, self._handle_error) 691 692 def process_patch(self, patch_string): 693 """Does lint on a single patch. 804 self._stderr_write(format_string % (filename, line_number, message, 805 category, confidence)) 806 807 def _process_file(self, processor, file_path, handle_style_error): 808 """Process the file using the given processor.""" 809 try: 810 # Support the UNIX convention of using "-" for stdin. Note that 811 # we are not opening the file with universal newline support 812 # (which codecs doesn't support anyway), so the resulting lines do 813 # contain trailing '\r' characters if we are reading a file that 814 # has CRLF endings. 815 # If after the split a trailing '\r' is present, it is removed 816 # below. If it is not expected to be present (i.e. os.linesep != 817 # '\r\n' as in Windows), a warning is issued below if this file 818 # is processed. 819 if file_path == '-': 820 lines = codecs.StreamReaderWriter(sys.stdin, 821 codecs.getreader('utf8'), 822 codecs.getwriter('utf8'), 823 'replace').read().split('\n') 824 else: 825 lines = codecs.open(file_path, 'r', 'utf8', 'replace').read().split('\n') 826 827 carriage_return_found = False 828 # Remove trailing '\r'. 829 for line_number in range(len(lines)): 830 if lines[line_number].endswith('\r'): 831 lines[line_number] = lines[line_number].rstrip('\r') 832 carriage_return_found = True 833 834 except IOError: 835 self._stderr_write("Skipping input '%s': Can't open for reading\n" % file_path) 836 return 837 838 processor.process(lines) 839 840 if carriage_return_found and os.linesep != '\r\n': 841 # FIXME: Make sure this error also shows up when checking 842 # patches, if appropriate. 843 # 844 # Use 0 for line_number since outputting only one error for 845 # potentially several lines. 846 handle_style_error(file_path, 0, 'whitespace/newline', 1, 847 'One or more unexpected \\r (^M) found;' 848 'better to use only a \\n') 849 850 def check_file(self, file_path, handle_style_error=None, process_file=None): 851 """Check style in the given file. 694 852 695 853 Args: 696 patch_string: A string of a patch. 854 file_path: A string that is the path of the file to process. 855 handle_style_error: The function to call when a style error 856 occurs. This parameter is meant for internal 857 use within this class. Defaults to the 858 style error handling method of this class. 859 process_file: The function to call to process the file. This 860 parameter should be used only for unit tests. 861 Defaults to the file processing method of this class. 862 863 """ 864 if handle_style_error is None: 865 handle_style_error = self._handle_style_error 866 867 if process_file is None: 868 process_file = self._process_file 869 870 dispatcher = ProcessorDispatcher() 871 872 if dispatcher.should_skip_without_warning(file_path): 873 return 874 if dispatcher.should_skip_with_warning(file_path): 875 self._stderr_write('Ignoring "%s": this file is exempt from the ' 876 "style guide.\n" % file_path) 877 return 878 879 verbosity = self.options.verbosity 880 processor = dispatcher.dispatch_processor(file_path, 881 handle_style_error, 882 verbosity) 883 process_file(processor, file_path, handle_style_error) 884 885 def check_patch(self, patch_string): 886 """Check style in the given patch. 887 888 Args: 889 patch_string: A string that is a patch string. 697 890 698 891 """ 699 892 patch = DiffParser(patch_string.splitlines()) 700 for filename, diff in patch.files.iteritems(): 701 file_extension = os.path.splitext(filename)[1] 893 for file_path, diff in patch.files.iteritems(): 702 894 line_numbers = set() 703 895 704 def error_for_patch(file name, line_number, category, confidence, message):896 def error_for_patch(file_path, line_number, category, confidence, message): 705 897 """Wrapper function of cpp_style.error for patches. 706 898 707 899 This function outputs errors only if the line number 708 900 corresponds to lines which are modified or added. 901 709 902 """ 710 903 if not line_numbers: … … 715 908 line_numbers.add(line[1]) 716 909 910 # FIXME: Make sure errors having line number zero are 911 # logged -- like carriage-return errors. 717 912 if line_number in line_numbers: 718 self._handle_error(filename, line_number, category, confidence, message) 719 720 # FIXME: Share this code with self.process_file(). 721 if cpp_style.can_handle(filename): 722 cpp_style.process_file(filename, error_for_patch, self.options.verbosity) 723 elif text_style.can_handle(filename): 724 text_style.process_file(filename, error_for_patch) 913 self._handle_style_error(file_path, line_number, category, confidence, message) 914 915 self.check_file(file_path, handle_style_error=error_for_patch) 916 -
trunk/WebKitTools/Scripts/webkitpy/style/checker_unittest.py
r53374 r53675 39 39 import checker as style 40 40 from checker import CategoryFilter 41 from checker import ProcessorDispatcher 41 42 from checker import ProcessorOptions 42 43 from checker import StyleChecker 44 from cpp_style import CppProcessor 45 from text_style import TextProcessor 43 46 44 47 class CategoryFilterTest(unittest.TestCase): … … 353 356 354 357 358 class ProcessorDispatcherSkipTest(unittest.TestCase): 359 360 """Tests the "should skip" methods of the ProcessorDispatcher class.""" 361 362 def test_should_skip_with_warning(self): 363 """Test should_skip_with_warning().""" 364 dispatcher = ProcessorDispatcher() 365 366 # Check a non-skipped file. 367 self.assertFalse(dispatcher.should_skip_with_warning("foo.txt")) 368 369 # Check skipped files. 370 paths_to_skip = [ 371 "gtk2drawing.c", 372 "gtk2drawing.h", 373 "JavaScriptCore/qt/api/qscriptengine_p.h", 374 "WebCore/platform/gtk/gtk2drawing.c", 375 "WebCore/platform/gtk/gtk2drawing.h", 376 "WebKit/gtk/tests/testatk.c", 377 "WebKit/qt/Api/qwebpage.h", 378 "WebKit/qt/tests/qwebsecurityorigin/tst_qwebsecurityorigin.cpp", 379 ] 380 381 for path in paths_to_skip: 382 self.assertTrue(dispatcher.should_skip_with_warning(path), 383 "Checking: " + path) 384 385 def test_should_skip_without_warning(self): 386 """Test should_skip_without_warning().""" 387 dispatcher = ProcessorDispatcher() 388 389 # Check a non-skipped file. 390 self.assertFalse(dispatcher.should_skip_without_warning("foo.txt")) 391 392 # Check skipped files. 393 paths_to_skip = [ 394 # LayoutTests folder 395 "LayoutTests/foo.txt", 396 ] 397 398 for path in paths_to_skip: 399 self.assertTrue(dispatcher.should_skip_without_warning(path), 400 "Checking: " + path) 401 402 403 class ProcessorDispatcherDispatchTest(unittest.TestCase): 404 405 """Tests dispatch_processor() method of ProcessorDispatcher class.""" 406 407 def mock_handle_style_error(self): 408 pass 409 410 def dispatch_processor(self, file_path): 411 """Call dispatch_processor() with the given file path.""" 412 dispatcher = ProcessorDispatcher() 413 processor = dispatcher.dispatch_processor(file_path, 414 self.mock_handle_style_error, 415 verbosity=3) 416 return processor 417 418 def assert_processor_none(self, file_path): 419 """Assert that the dispatched processor is None.""" 420 processor = self.dispatch_processor(file_path) 421 self.assertTrue(processor is None, 'Checking: "%s"' % file_path) 422 423 def assert_processor(self, file_path, expected_class): 424 """Assert the type of the dispatched processor.""" 425 processor = self.dispatch_processor(file_path) 426 got_class = processor.__class__ 427 self.assertEquals(got_class, expected_class, 428 'For path "%(file_path)s" got %(got_class)s when ' 429 "expecting %(expected_class)s." 430 % {"file_path": file_path, 431 "got_class": got_class, 432 "expected_class": expected_class}) 433 434 def assert_processor_cpp(self, file_path): 435 """Assert that the dispatched processor is a CppProcessor.""" 436 self.assert_processor(file_path, CppProcessor) 437 438 def assert_processor_text(self, file_path): 439 """Assert that the dispatched processor is a TextProcessor.""" 440 self.assert_processor(file_path, TextProcessor) 441 442 def test_cpp_paths(self): 443 """Test paths that should be checked as C++.""" 444 paths = [ 445 "-", 446 "foo.c", 447 "foo.cpp", 448 "foo.h", 449 ] 450 451 for path in paths: 452 self.assert_processor_cpp(path) 453 454 # Check processor attributes on a typical input. 455 file_base = "foo" 456 file_extension = "c" 457 file_path = file_base + "." + file_extension 458 self.assert_processor_cpp(file_path) 459 processor = self.dispatch_processor(file_path) 460 self.assertEquals(processor.file_extension, file_extension) 461 self.assertEquals(processor.file_path, file_path) 462 self.assertEquals(processor.handle_style_error, self.mock_handle_style_error) 463 self.assertEquals(processor.verbosity, 3) 464 # Check "-" for good measure. 465 file_base = "-" 466 file_extension = "" 467 file_path = file_base 468 self.assert_processor_cpp(file_path) 469 processor = self.dispatch_processor(file_path) 470 self.assertEquals(processor.file_extension, file_extension) 471 self.assertEquals(processor.file_path, file_path) 472 473 def test_text_paths(self): 474 """Test paths that should be checked as text.""" 475 paths = [ 476 "ChangeLog", 477 "foo.css", 478 "foo.html", 479 "foo.idl", 480 "foo.js", 481 "foo.mm", 482 "foo.php", 483 "foo.pm", 484 "foo.py", 485 "foo.txt", 486 "FooChangeLog.bak", 487 "WebCore/ChangeLog", 488 "WebCore/inspector/front-end/inspector.js", 489 "WebKitTools/Scripts/check-webkit=style", 490 "WebKitTools/Scripts/modules/text_style.py", 491 ] 492 493 for path in paths: 494 self.assert_processor_text(path) 495 496 # Check processor attributes on a typical input. 497 file_base = "foo" 498 file_extension = "css" 499 file_path = file_base + "." + file_extension 500 self.assert_processor_text(file_path) 501 processor = self.dispatch_processor(file_path) 502 self.assertEquals(processor.file_path, file_path) 503 self.assertEquals(processor.handle_style_error, self.mock_handle_style_error) 504 505 def test_none_paths(self): 506 """Test paths that have no file type..""" 507 paths = [ 508 "Makefile", 509 "foo.png", 510 "foo.exe", 511 ] 512 513 for path in paths: 514 self.assert_processor_none(path) 515 516 355 517 class StyleCheckerTest(unittest.TestCase): 356 518 … … 358 520 359 521 Attributes: 360 error_message: A string that is the last error message reported 361 by the test StyleChecker instance. 522 error_messages: A string containing all of the warning messages 523 written to the mock_stderr_write method of 524 this class. 362 525 363 526 """ 364 527 365 error_message = "" 366 367 def mock_write_error(self, error_message): 368 """Store an error message without printing it.""" 369 self.error_message = error_message 528 def setUp(self): 529 self.error_messages = "" 530 531 def mock_stderr_write(self, error_message): 532 """A mock sys.stderr.write.""" 533 self.error_messages = error_message 370 534 pass 371 535 536 def mock_handle_style_error(self): 537 pass 538 372 539 def style_checker(self, options): 373 return StyleChecker(options, self.mock_ write_error)540 return StyleChecker(options, self.mock_stderr_write) 374 541 375 542 def test_init(self): … … 382 549 383 550 def write_sample_error(self, style_checker, error_confidence): 384 """Write an error to the given style _checker."""385 style_checker._handle_ error(filename="filename",386 line_number=1,387 category="category",388 confidence=error_confidence,389 message="message")390 391 def test_handle_ error(self):392 """Test _handle r_error() function."""551 """Write an error to the given style checker.""" 552 style_checker._handle_style_error(filename="filename", 553 line_number=1, 554 category="category", 555 confidence=error_confidence, 556 message="message") 557 558 def test_handle_style_error(self): 559 """Test _handle_style_error() function.""" 393 560 options = ProcessorOptions(output_format="emacs", 394 561 verbosity=3) … … 397 564 # Verify initialized properly. 398 565 self.assertEquals(style_checker.error_count, 0) 399 self.assertEquals(self.error_message , "")566 self.assertEquals(self.error_messages, "") 400 567 401 568 # Check that should_print_error is getting called appropriately. 402 569 self.write_sample_error(style_checker, 2) 403 570 self.assertEquals(style_checker.error_count, 0) # Error confidence too low. 404 self.assertEquals(self.error_message , "")571 self.assertEquals(self.error_messages, "") 405 572 406 573 self.write_sample_error(style_checker, 3) 407 574 self.assertEquals(style_checker.error_count, 1) # Error confidence just high enough. 408 self.assertEquals(self.error_message, "filename:1: message [category] [3]\n") 575 self.assertEquals(self.error_messages, "filename:1: message [category] [3]\n") 576 577 # Clear previous errors. 578 self.error_messages = "" 409 579 410 580 # Check "vs7" output format. … … 412 582 self.write_sample_error(style_checker, 3) 413 583 self.assertEquals(style_checker.error_count, 2) # Error confidence just high enough. 414 self.assertEquals(self.error_message, "filename(1): message [category] [3]\n") 584 self.assertEquals(self.error_messages, "filename(1): message [category] [3]\n") 585 586 587 class StyleCheckerCheckFileTest(unittest.TestCase): 588 589 """Test the check_file() method of the StyleChecker class. 590 591 The check_file() method calls its process_file parameter when 592 given a file that should not be skipped. 593 594 The "got_*" attributes of this class are the parameters passed 595 to process_file by calls to check_file() made by this test 596 class. These attributes allow us to check the parameter values 597 passed internally to the process_file function. 598 599 Attributes: 600 got_file_path: The file_path parameter passed by check_file() 601 to its process_file parameter. 602 got_handle_style_error: The handle_style_error parameter passed 603 by check_file() to its process_file 604 parameter. 605 got_processor: The processor parameter passed by check_file() to 606 its process_file parameter. 607 warning_messages: A string containing all of the warning messages 608 written to the mock_stderr_write method of 609 this class. 610 611 """ 612 def setUp(self): 613 self.got_file_path = None 614 self.got_handle_style_error = None 615 self.got_processor = None 616 self.warning_messages = "" 617 618 def mock_stderr_write(self, warning_message): 619 self.warning_messages += warning_message 620 621 def mock_handle_style_error(self): 622 pass 623 624 def mock_process_file(self, processor, file_path, handle_style_error): 625 """A mock _process_file(). 626 627 See the documentation for this class for more information 628 on this function. 629 630 """ 631 self.got_file_path = file_path 632 self.got_handle_style_error = handle_style_error 633 self.got_processor = processor 634 635 def assert_attributes(self, 636 expected_file_path, 637 expected_handle_style_error, 638 expected_processor, 639 expected_warning_messages): 640 """Assert that the attributes of this class equal the given values.""" 641 self.assertEquals(self.got_file_path, expected_file_path) 642 self.assertEquals(self.got_handle_style_error, expected_handle_style_error) 643 self.assertEquals(self.got_processor, expected_processor) 644 self.assertEquals(self.warning_messages, expected_warning_messages) 645 646 def call_check_file(self, file_path): 647 """Call the check_file() method of a test StyleChecker instance.""" 648 # Confirm that the attributes are reset. 649 self.assert_attributes(None, None, None, "") 650 651 # Create a test StyleChecker instance. 652 # 653 # The verbosity attribute is the only ProcessorOptions 654 # attribute that needs to be checked in this test. 655 # This is because it is the only option is directly 656 # passed to the constructor of a style processor. 657 options = ProcessorOptions(verbosity=3) 658 659 style_checker = StyleChecker(options, self.mock_stderr_write) 660 661 style_checker.check_file(file_path, 662 self.mock_handle_style_error, 663 self.mock_process_file) 664 665 def test_check_file_on_skip_without_warning(self): 666 """Test check_file() for a skipped-without-warning file.""" 667 668 file_path = "LayoutTests/foo.txt" 669 670 dispatcher = ProcessorDispatcher() 671 # Confirm that the input file is truly a skipped-without-warning file. 672 self.assertTrue(dispatcher.should_skip_without_warning(file_path)) 673 674 # Check the outcome. 675 self.call_check_file(file_path) 676 self.assert_attributes(None, None, None, "") 677 678 def test_check_file_on_skip_with_warning(self): 679 """Test check_file() for a skipped-with-warning file.""" 680 681 file_path = "gtk2drawing.c" 682 683 dispatcher = ProcessorDispatcher() 684 # Check that the input file is truly a skipped-with-warning file. 685 self.assertTrue(dispatcher.should_skip_with_warning(file_path)) 686 687 # Check the outcome. 688 self.call_check_file(file_path) 689 self.assert_attributes(None, None, None, 690 'Ignoring "gtk2drawing.c": this file is exempt from the style guide.\n') 691 692 def test_check_file_on_non_skipped(self): 693 694 # We use a C++ file since by using a CppProcessor, we can check 695 # that all of the possible information is getting passed to 696 # process_file (in particular, the verbosity). 697 file_base = "foo" 698 file_extension = "cpp" 699 file_path = file_base + "." + file_extension 700 701 dispatcher = ProcessorDispatcher() 702 # Check that the input file is truly a C++ file. 703 self.assertEquals(dispatcher._file_type(file_path), style.FileType.CPP) 704 705 # Check the outcome. 706 self.call_check_file(file_path) 707 708 expected_processor = CppProcessor(file_path, file_extension, self.mock_handle_style_error, 3) 709 710 self.assert_attributes(file_path, 711 self.mock_handle_style_error, 712 expected_processor, 713 "") 415 714 416 715 … … 419 718 420 719 unittest.main() 720 -
trunk/WebKitTools/Scripts/webkitpy/style/cpp_style.py
r53636 r53675 5 5 # Copyright (C) 2009 Torch Mobile Inc. 6 6 # Copyright (C) 2009 Apple Inc. All rights reserved. 7 # Copyright (C) 2010 Chris Jerdonek (cjerdonek@webkit.org) 7 8 # 8 9 # Redistribution and use in source and binary forms, with or without … … 2821 2822 2822 2823 2823 def process_file_data(filename, file_extension, lines, error, verbosity):2824 def _process_lines(filename, file_extension, lines, error, verbosity): 2824 2825 """Performs lint checks and reports any errors to the given error function. 2825 2826 … … 2860 2861 2861 2862 2862 def process_file(filename, error, verbosity): 2863 """Performs cpp_style on a single file. 2864 2865 Args: 2866 filename: The name of the file to parse. 2867 error: The function to call with any errors found. 2868 verbosity: An integer that is the verbosity level to use while 2869 checking style. 2870 """ 2871 try: 2872 # Support the UNIX convention of using "-" for stdin. Note that 2873 # we are not opening the file with universal newline support 2874 # (which codecs doesn't support anyway), so the resulting lines do 2875 # contain trailing '\r' characters if we are reading a file that 2876 # has CRLF endings. 2877 # If after the split a trailing '\r' is present, it is removed 2878 # below. If it is not expected to be present (i.e. os.linesep != 2879 # '\r\n' as in Windows), a warning is issued below if this file 2880 # is processed. 2881 2882 if filename == '-': 2883 lines = codecs.StreamReaderWriter(sys.stdin, 2884 codecs.getreader('utf8'), 2885 codecs.getwriter('utf8'), 2886 'replace').read().split('\n') 2887 else: 2888 lines = codecs.open(filename, 'r', 'utf8', 'replace').read().split('\n') 2889 2890 carriage_return_found = False 2891 # Remove trailing '\r'. 2892 for line_number in range(len(lines)): 2893 if lines[line_number].endswith('\r'): 2894 lines[line_number] = lines[line_number].rstrip('\r') 2895 carriage_return_found = True 2896 2897 except IOError: 2898 sys.stderr.write( 2899 "Skipping input '%s': Can't open for reading\n" % filename) 2900 return 2901 2902 # Note, if no dot is found, this will give the entire filename as the ext. 2903 file_extension = filename[filename.rfind('.') + 1:] 2904 2905 # When reading from stdin, the extension is unknown, so no cpp_style tests 2906 # should rely on the extension. 2907 if (filename != '-' and not can_handle(filename)): 2908 sys.stderr.write('Ignoring %s; not a .cpp, .c or .h file\n' % filename) 2909 elif is_exempt(filename): 2910 sys.stderr.write('Ignoring %s; This file is exempt from the style guide.\n' % filename) 2911 else: 2912 process_file_data(filename, file_extension, lines, error, verbosity) 2913 if carriage_return_found and os.linesep != '\r\n': 2914 # Use 0 for line_number since outputing only one error for potentially 2915 # several lines. 2916 error(filename, 0, 'whitespace/newline', 1, 2917 'One or more unexpected \\r (^M) found;' 2918 'better to use only a \\n') 2919 2920 2921 def can_handle(filename): 2922 """Checks if this module supports for the specified file type. 2923 2924 Args: 2925 filename: A filename. It may contain directory names. 2926 """ 2927 return os.path.splitext(filename)[1] in ('.h', '.cpp', '.c') 2928 2929 2930 def is_exempt(filename): 2931 """Checks if the given file is exempt from the style guide. For example, 2932 some files are purposefully mantained in Mozilla style to ease future 2933 merges. 2934 2935 Args: 2936 filename: A filename. It may contain directory names. 2937 """ 2938 if (filename.find('WebKit/qt/Api/') >= 0 2939 or filename.find('JavaScriptCore/qt/api/') >= 0 2940 or filename.find('WebKit/qt/tests/') >= 0 2941 or filename.find('WebKit/gtk/tests/') >= 0): 2942 # The Qt API and the Qt and Gtk tests do not follow WebKit style. 2863 class CppProcessor(object): 2864 2865 """Processes C++ lines for checking style.""" 2866 2867 def __init__(self, file_path, file_extension, handle_style_error, verbosity): 2868 """Create a CppProcessor instance. 2869 2870 Args: 2871 file_extension: A string that is the file extension, without 2872 the leading dot. 2873 2874 """ 2875 self.file_extension = file_extension 2876 self.file_path = file_path 2877 self.handle_style_error = handle_style_error 2878 self.verbosity = verbosity 2879 2880 # Useful for unit testing. 2881 def __eq__(self, other): 2882 """Return whether this CppProcessor instance is equal to another.""" 2883 if self.file_extension != other.file_extension: 2884 return False 2885 if self.file_path != other.file_path: 2886 return False 2887 if self.handle_style_error != other.handle_style_error: 2888 return False 2889 if self.verbosity != other.verbosity: 2890 return False 2891 2943 2892 return True 2944 2893 2945 return os.path.basename(filename) in ( 2946 'gtk2drawing.c', 2947 'gtk2drawing.h', 2948 ) 2894 # Useful for unit testing. 2895 def __ne__(self, other): 2896 # Python does not automatically deduce __ne__() from __eq__(). 2897 return not self.__eq__(other) 2898 2899 def process(self, lines): 2900 _process_lines(self.file_path, self.file_extension, lines, 2901 self.handle_style_error, self.verbosity) 2902 2903 2904 # FIXME: Remove this function (requires refactoring unit tests). 2905 def process_file_data(filename, file_extension, lines, error, verbosity): 2906 processor = CppProcessor(filename, file_extension, error, verbosity) 2907 processor.process(lines) 2908 -
trunk/WebKitTools/Scripts/webkitpy/style/cpp_style_unittest.py
r53636 r53675 5 5 # Copyright (C) 2009 Torch Mobile Inc. 6 6 # Copyright (C) 2009 Apple Inc. All rights reserved. 7 # Copyright (C) 2010 Chris Jerdonek (cjerdonek@webkit.org) 7 8 # 8 9 # Redistribution and use in source and binary forms, with or without … … 42 43 import unittest 43 44 import cpp_style 45 from cpp_style import CppProcessor 46 44 47 # FIXME: Remove the need to import anything from checker. See the 45 48 # FIXME notes near the STYLE_CATEGORIES definition for a … … 3607 3610 3608 3611 3609 def test_can_handle(self): 3610 """Tests for cpp_style.can_handle().""" 3611 self.assert_(not cpp_style.can_handle('')) 3612 self.assert_(cpp_style.can_handle('foo.h')) 3613 self.assert_(not cpp_style.can_handle('foo.hpp')) 3614 self.assert_(cpp_style.can_handle('foo.c')) 3615 self.assert_(cpp_style.can_handle('foo.cpp')) 3616 self.assert_(not cpp_style.can_handle('foo.cc')) 3617 self.assert_(not cpp_style.can_handle('foo.cxx')) 3618 self.assert_(not cpp_style.can_handle('foo.C')) 3619 self.assert_(not cpp_style.can_handle('foo.mm')) 3620 self.assert_(not cpp_style.can_handle('-')) 3621 3622 def test_is_exempt(self): 3623 """Tests for cpp_style.is_exempt().""" 3624 self.assert_(not cpp_style.is_exempt('')) 3625 self.assert_(not cpp_style.is_exempt('foo.h')) 3626 self.assert_(not cpp_style.is_exempt('foo.hpp')) 3627 self.assert_(not cpp_style.is_exempt('foo.c')) 3628 self.assert_(not cpp_style.is_exempt('foo.cpp')) 3629 self.assert_(not cpp_style.is_exempt('-')) 3630 self.assert_(cpp_style.is_exempt('gtk2drawing.h')) 3631 self.assert_(cpp_style.is_exempt('WebCore/platform/gtk/gtk2drawing.h')) 3632 self.assert_(cpp_style.is_exempt('gtk2drawing.c')) 3633 self.assert_(cpp_style.is_exempt('WebCore/platform/gtk/gtk2drawing.c')) 3634 self.assert_(cpp_style.is_exempt('WebKit/qt/Api/qwebpage.h')) 3635 self.assert_(cpp_style.is_exempt('JavaScriptCore/qt/api/qscriptengine_p.h')) 3636 self.assert_(cpp_style.is_exempt('WebKit/qt/tests/qwebsecurityorigin/tst_qwebsecurityorigin.cpp')) 3637 self.assert_(cpp_style.is_exempt('WebKit/gtk/tests/testatk.c')) 3612 class CppProcessorTest(unittest.TestCase): 3613 3614 """Tests CppProcessor class.""" 3615 3616 def mock_handle_style_error(self): 3617 pass 3618 3619 def _processor(self): 3620 return CppProcessor("foo", "h", self.mock_handle_style_error, 3) 3621 3622 def test_init(self): 3623 """Test __init__ constructor.""" 3624 processor = self._processor() 3625 self.assertEquals(processor.file_extension, "h") 3626 self.assertEquals(processor.file_path, "foo") 3627 self.assertEquals(processor.handle_style_error, self.mock_handle_style_error) 3628 self.assertEquals(processor.verbosity, 3) 3629 3630 def test_eq(self): 3631 """Test __eq__ equality function.""" 3632 processor1 = self._processor() 3633 processor2 = self._processor() 3634 3635 # == calls __eq__. 3636 self.assertTrue(processor1 == processor2) 3637 3638 def mock_handle_style_error2(self): 3639 pass 3640 3641 # Verify that a difference in any argument cause equality to fail. 3642 processor = CppProcessor("foo", "h", self.mock_handle_style_error, 3) 3643 self.assertFalse(processor == CppProcessor("bar", "h", self.mock_handle_style_error, 3)) 3644 self.assertFalse(processor == CppProcessor("foo", "c", self.mock_handle_style_error, 3)) 3645 self.assertFalse(processor == CppProcessor("foo", "h", mock_handle_style_error2, 3)) 3646 self.assertFalse(processor == CppProcessor("foo", "h", self.mock_handle_style_error, 4)) 3647 3648 def test_ne(self): 3649 """Test __ne__ inequality function.""" 3650 processor1 = self._processor() 3651 processor2 = self._processor() 3652 3653 # != calls __ne__. 3654 # By default, __ne__ always returns true on different objects. 3655 # Thus, just check the distinguishing case to verify that the 3656 # code defines __ne__. 3657 self.assertFalse(processor1 != processor2) 3658 3638 3659 3639 3660 def tearDown(): -
trunk/WebKitTools/Scripts/webkitpy/style/text_style.py
r53251 r53675 1 1 # Copyright (C) 2009 Google Inc. All rights reserved. 2 # Copyright (C) 2010 Chris Jerdonek (cjerdonek@webkit.org) 2 3 # 3 4 # Redistribution and use in source and binary forms, with or without … … 27 28 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 29 29 """Does WebKit-lint on text files. 30 31 This module shares error count, filter setting, output setting, etc. with cpp_style. 32 """ 33 34 import codecs 35 import os.path 36 import sys 37 38 import cpp_style 30 """Checks WebKit style for text files.""" 39 31 40 32 41 def process_file_data(filename, lines, error): 42 """Performs lint check for text on the specified lines. 33 class TextProcessor(object): 43 34 44 It reports errors to the given error function. 45 """ 46 lines = (['// adjust line numbers to make the first line 1.'] + lines) 35 """Processes text lines for checking style.""" 47 36 48 # FIXME: share with cpp_style.check_style() 49 for line_number, line in enumerate(lines): 50 if '\t' in line: 51 error(filename, line_number, 'whitespace/tab', 5, 'Line contains tab character.') 37 def __init__(self, file_path, handle_style_error): 38 self.file_path = file_path 39 self.handle_style_error = handle_style_error 40 41 def process(self, lines): 42 lines = (["// adjust line numbers to make the first line 1."] + lines) 43 44 # FIXME: share with cpp_style. 45 for line_number, line in enumerate(lines): 46 if "\t" in line: 47 self.handle_style_error(self.file_path, line_number, 48 "whitespace/tab", 5, 49 "Line contains tab character.") 52 50 53 51 54 def process_file(filename, error): 55 """Performs lint check for text on a single file.""" 56 if (not can_handle(filename)): 57 sys.stderr.write('Ignoring %s; not a supported file\n' % filename) 58 return 52 # FIXME: Remove this function (requires refactoring unit tests). 53 def process_file_data(filename, lines, error): 54 processor = TextProcessor(filename, error) 55 processor.process(lines) 59 56 60 # FIXME: share code with cpp_style.process_file().61 try:62 # Do not support for filename='-'. cpp_style handles it.63 lines = codecs.open(filename, 'r', 'utf8', 'replace').read().split('\n')64 except IOError:65 sys.stderr.write("Skipping input '%s': Can't open for reading\n" % filename)66 return67 process_file_data(filename, lines, error)68 69 70 def can_handle(filename):71 """Checks if this module supports the specified file type.72 73 Args:74 filename: A filename. It may contain directory names.75 """76 return ("ChangeLog" in filename77 or "WebKitTools/Scripts/" in filename78 or os.path.splitext(filename)[1] in ('.css', '.html', '.idl', '.js', '.mm', '.php', '.pm', '.py', '.txt')) and not "LayoutTests/" in filename -
trunk/WebKitTools/Scripts/webkitpy/style/text_style_unittest.py
r52906 r53675 33 33 34 34 import text_style 35 35 from text_style import TextProcessor 36 36 37 37 class TextStyleTestCase(unittest.TestCase): … … 77 77 78 78 79 def test_can_handle(self): 80 """Tests for text_style.can_handle().""" 81 self.assert_(not text_style.can_handle('')) 82 self.assert_(not text_style.can_handle('-')) 83 self.assert_(text_style.can_handle('ChangeLog')) 84 self.assert_(text_style.can_handle('WebCore/ChangeLog')) 85 self.assert_(text_style.can_handle('FooChangeLog.bak')) 86 self.assert_(text_style.can_handle('WebKitTools/Scripts/check-webkit=style')) 87 self.assert_(text_style.can_handle('WebKitTools/Scripts/modules/text_style.py')) 88 self.assert_(not text_style.can_handle('WebKitTools/Scripts')) 79 class TextProcessorTest(unittest.TestCase): 89 80 90 self.assert_(text_style.can_handle('foo.css')) 91 self.assert_(text_style.can_handle('foo.html')) 92 self.assert_(text_style.can_handle('foo.idl')) 93 self.assert_(text_style.can_handle('foo.js')) 94 self.assert_(text_style.can_handle('WebCore/inspector/front-end/inspector.js')) 95 self.assert_(text_style.can_handle('foo.mm')) 96 self.assert_(text_style.can_handle('foo.php')) 97 self.assert_(text_style.can_handle('foo.pm')) 98 self.assert_(text_style.can_handle('foo.py')) 99 self.assert_(text_style.can_handle('foo.txt')) 100 self.assert_(not text_style.can_handle('foo.c')) 101 self.assert_(not text_style.can_handle('foo.c')) 102 self.assert_(not text_style.can_handle('foo.c')) 103 self.assert_(not text_style.can_handle('foo.png')) 104 self.assert_(not text_style.can_handle('foo.c/bar.png')) 105 self.assert_(not text_style.can_handle('WebKit/English.lproj/Localizable.strings')) 106 self.assert_(not text_style.can_handle('Makefile')) 107 self.assert_(not text_style.can_handle('WebCore/Android.mk')) 108 self.assert_(not text_style.can_handle('LayoutTests/inspector/console-tests.js')) 81 """Tests TextProcessor class.""" 82 83 def mock_handle_style_error(self): 84 pass 85 86 def test_init(self): 87 """Test __init__ constructor.""" 88 processor = TextProcessor("foo.txt", self.mock_handle_style_error) 89 self.assertEquals(processor.file_path, "foo.txt") 90 self.assertEquals(processor.handle_style_error, self.mock_handle_style_error) 109 91 110 92
Note: See TracChangeset
for help on using the changeset viewer.