2 # -*- coding: utf-8; -*-
4 # Copyright (C) 2009 Google Inc. All rights reserved.
5 # Copyright (C) 2009 Torch Mobile Inc.
6 # Copyright (C) 2009 Apple Inc. All rights reserved.
7 # Copyright (C) 2010 Chris Jerdonek (chris.jerdonek@gmail.com)
9 # Redistribution and use in source and binary forms, with or without
10 # modification, are permitted provided that the following conditions are
13 # * Redistributions of source code must retain the above copyright
14 # notice, this list of conditions and the following disclaimer.
15 # * Redistributions in binary form must reproduce the above
16 # copyright notice, this list of conditions and the following disclaimer
17 # in the documentation and/or other materials provided with the
19 # * Neither the name of Google Inc. nor the names of its
20 # contributors may be used to endorse or promote products derived from
21 # this software without specific prior written permission.
23 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24 # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25 # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
26 # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
27 # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
28 # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
29 # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
30 # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
31 # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
32 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
33 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
35 """Unit tests for style.py."""
41 import checker as style
42 from webkitpy.common.system.logtesting import LogTesting, TestLogStream
43 from checker import _BASE_FILTER_RULES
44 from checker import _MAX_REPORTS_PER_CATEGORY
45 from checker import _PATH_RULES_SPECIFIER as PATH_RULES_SPECIFIER
46 from checker import _all_categories
47 from checker import check_webkit_style_configuration
48 from checker import check_webkit_style_parser
49 from checker import configure_logging
50 from checker import CheckerDispatcher
51 from checker import ProcessorBase
52 from checker import StyleProcessor
53 from checker import StyleProcessorConfiguration
54 from checkers.changelog import ChangeLogChecker
55 from checkers.cpp import CppChecker
56 from checkers.python import PythonChecker
57 from checkers.text import TextChecker
58 from checkers.xml import XMLChecker
59 from error_handlers import DefaultStyleErrorHandler
60 from filter import validate_filter_rules
61 from filter import FilterConfiguration
62 from optparser import ArgumentParser
63 from optparser import CommandOptionValues
64 from webkitpy.common.system.logtesting import LoggingTestCase
65 from webkitpy.style.filereader import TextFileReader
68 class ConfigureLoggingTestBase(unittest.TestCase):
70 """Base class for testing configure_logging().
72 Sub-classes should implement:
74 is_verbose: The is_verbose value to pass to configure_logging().
79 is_verbose = self.is_verbose
81 log_stream = TestLogStream(self)
83 # Use a logger other than the root logger or one prefixed with
84 # webkit so as not to conflict with test-webkitpy logging.
85 logger = logging.getLogger("unittest")
87 # Configure the test logger not to pass messages along to the
88 # root logger. This prevents test messages from being
89 # propagated to loggers used by test-webkitpy logging (e.g.
91 logger.propagate = False
93 self._handlers = configure_logging(stream=log_stream, logger=logger,
94 is_verbose=is_verbose)
96 self._log_stream = log_stream
99 """Reset logging to its original state.
101 This method ensures that the logging configuration set up
102 for a unit test does not affect logging in other unit tests.
106 for handler in self._handlers:
107 logger.removeHandler(handler)
109 def assert_log_messages(self, messages):
110 """Assert that the logged messages equal the given messages."""
111 self._log_stream.assertMessages(messages)
114 class ConfigureLoggingTest(ConfigureLoggingTestBase):
116 """Tests the configure_logging() function."""
120 def test_warning_message(self):
121 self._log.warn("test message")
122 self.assert_log_messages(["WARNING: test message\n"])
124 def test_below_warning_message(self):
125 # We test the boundary case of a logging level equal to 29.
126 # In practice, we will probably only be calling log.info(),
127 # which corresponds to a logging level of 20.
128 level = logging.WARNING - 1 # Equals 29.
129 self._log.log(level, "test message")
130 self.assert_log_messages(["test message\n"])
132 def test_debug_message(self):
133 self._log.debug("test message")
134 self.assert_log_messages([])
136 def test_two_messages(self):
137 self._log.info("message1")
138 self._log.info("message2")
139 self.assert_log_messages(["message1\n", "message2\n"])
142 class ConfigureLoggingVerboseTest(ConfigureLoggingTestBase):
144 """Tests the configure_logging() function with is_verbose True."""
148 def test_debug_message(self):
149 self._log.debug("test message")
150 self.assert_log_messages(["unittest: DEBUG test message\n"])
153 class GlobalVariablesTest(unittest.TestCase):
155 """Tests validity of the global variables."""
157 def _all_categories(self):
158 return _all_categories()
161 return style._check_webkit_style_defaults()
163 def test_webkit_base_filter_rules(self):
164 base_filter_rules = _BASE_FILTER_RULES
165 defaults = self.defaults()
167 validate_filter_rules(base_filter_rules, self._all_categories())
168 # Also do some additional checks.
169 for rule in base_filter_rules:
170 # Check no leading or trailing white space.
171 self.assertEquals(rule, rule.strip())
172 # All categories are on by default, so defaults should
174 self.assertTrue(rule.startswith('-'))
175 # Check no rule occurs twice.
176 self.assertFalse(rule in already_seen)
177 already_seen.append(rule)
179 def test_defaults(self):
180 """Check that default arguments are valid."""
181 default_options = self.defaults()
183 # FIXME: We should not need to call parse() to determine
184 # whether the default arguments are valid.
185 parser = ArgumentParser(all_categories=self._all_categories(),
186 base_filter_rules=[],
187 default_options=default_options)
188 # No need to test the return value here since we test parse()
189 # on valid arguments elsewhere.
191 # The default options are valid: no error or SystemExit.
192 parser.parse(args=[])
194 def test_path_rules_specifier(self):
195 all_categories = self._all_categories()
196 for (sub_paths, path_rules) in PATH_RULES_SPECIFIER:
197 validate_filter_rules(path_rules, self._all_categories())
199 config = FilterConfiguration(path_specific=PATH_RULES_SPECIFIER)
201 def assertCheck(path, category):
202 """Assert that the given category should be checked."""
203 message = ('Should check category "%s" for path "%s".'
205 self.assertTrue(config.should_check(category, path))
207 def assertNoCheck(path, category):
208 """Assert that the given category should not be checked."""
209 message = ('Should not check category "%s" for path "%s".'
211 self.assertFalse(config.should_check(category, path), message)
213 assertCheck("random_path.cpp",
215 assertNoCheck("Tools/WebKitAPITest/main.cpp",
217 assertCheck("random_path.cpp",
218 "readability/naming")
219 assertNoCheck("Source/WebKit/gtk/webkit/webkit.h",
220 "readability/naming")
221 assertNoCheck("Tools/DumpRenderTree/gtk/DumpRenderTree.cpp",
223 assertNoCheck("Source/WebKit/efl/ewk/ewk_view.h",
224 "readability/naming")
225 assertNoCheck("Source/WebCore/css/CSSParser.cpp",
226 "readability/naming")
228 # Test if Qt exceptions are indeed working
229 assertCheck("Source/JavaScriptCore/qt/api/qscriptengine.cpp",
230 "readability/braces")
231 assertCheck("Source/WebKit/qt/Api/qwebpage.cpp",
232 "readability/braces")
233 assertCheck("Source/WebKit/qt/tests/qwebelement/tst_qwebelement.cpp",
234 "readability/braces")
235 assertCheck("Source/WebKit/qt/declarative/platformplugin/WebPlugin.cpp",
236 "readability/braces")
237 assertCheck("Source/WebKit/qt/examples/platformplugin/WebPlugin.cpp",
238 "readability/braces")
239 assertCheck("Source/WebKit/qt/symbian/platformplugin/WebPlugin.cpp",
240 "readability/braces")
241 assertNoCheck("Source/JavaScriptCore/qt/api/qscriptengine.cpp",
242 "readability/naming")
243 assertNoCheck("Source/JavaScriptCore/qt/benchmarks"
244 "/qscriptengine/tst_qscriptengine.cpp",
245 "readability/naming")
246 assertNoCheck("Source/WebKit/qt/Api/qwebpage.cpp",
247 "readability/naming")
248 assertNoCheck("Source/WebKit/qt/tests/qwebelement/tst_qwebelement.cpp",
249 "readability/naming")
250 assertNoCheck("Source/WebKit/qt/declarative/platformplugin/WebPlugin.cpp",
251 "readability/naming")
252 assertNoCheck("Source/WebKit/qt/examples/platformplugin/WebPlugin.cpp",
253 "readability/naming")
254 assertNoCheck("Source/WebKit/qt/symbian/platformplugin/WebPlugin.cpp",
255 "build/header_guard")
257 assertNoCheck("Tools/MiniBrowser/qt/UrlLoader.cpp",
260 assertNoCheck("Source/WebCore/ForwardingHeaders/debugger/Debugger.h",
261 "build/header_guard")
263 # Third-party Python code: webkitpy/thirdparty
264 path = "Tools/Scripts/webkitpy/thirdparty/mock.py"
265 assertNoCheck(path, "build/include")
266 assertNoCheck(path, "pep8/E401") # A random pep8 category.
267 assertCheck(path, "pep8/W191")
268 assertCheck(path, "pep8/W291")
269 assertCheck(path, "whitespace/carriage_return")
271 def test_max_reports_per_category(self):
272 """Check that _MAX_REPORTS_PER_CATEGORY is valid."""
273 all_categories = self._all_categories()
274 for category in _MAX_REPORTS_PER_CATEGORY.iterkeys():
275 self.assertTrue(category in all_categories,
276 'Key "%s" is not a category' % category)
279 class CheckWebKitStyleFunctionTest(unittest.TestCase):
281 """Tests the functions with names of the form check_webkit_style_*."""
283 def test_check_webkit_style_configuration(self):
284 # Exercise the code path to make sure the function does not error out.
285 option_values = CommandOptionValues()
286 configuration = check_webkit_style_configuration(option_values)
288 def test_check_webkit_style_parser(self):
289 # Exercise the code path to make sure the function does not error out.
290 parser = check_webkit_style_parser()
293 class CheckerDispatcherSkipTest(unittest.TestCase):
295 """Tests the "should skip" methods of the CheckerDispatcher class."""
298 self._dispatcher = CheckerDispatcher()
300 def test_should_skip_with_warning(self):
301 """Test should_skip_with_warning()."""
302 # Check a non-skipped file.
303 self.assertFalse(self._dispatcher.should_skip_with_warning("foo.txt"))
305 # Check skipped files.
309 "Source/WebCore/platform/gtk/gtk2drawing.c",
310 "Source/WebCore/platform/gtk/gtkdrawing.h",
311 "Source/WebKit/gtk/tests/testatk.c",
314 for path in paths_to_skip:
315 self.assertTrue(self._dispatcher.should_skip_with_warning(path),
318 def _assert_should_skip_without_warning(self, path, is_checker_none,
320 # Check the file type before asserting the return value.
321 checker = self._dispatcher.dispatch(file_path=path,
322 handle_style_error=None,
324 message = 'while checking: %s' % path
325 self.assertEquals(checker is None, is_checker_none, message)
326 self.assertEquals(self._dispatcher.should_skip_without_warning(path),
329 def test_should_skip_without_warning__true(self):
330 """Test should_skip_without_warning() for True return values."""
331 # Check a file with NONE file type.
332 path = 'foo.asdf' # Non-sensical file extension.
333 self._assert_should_skip_without_warning(path,
334 is_checker_none=True,
337 # Check files with non-NONE file type. These examples must be
338 # drawn from the _SKIPPED_FILES_WITHOUT_WARNING configuration
340 path = os.path.join('LayoutTests', 'foo.txt')
341 self._assert_should_skip_without_warning(path,
342 is_checker_none=False,
345 def test_should_skip_without_warning__false(self):
346 """Test should_skip_without_warning() for False return values."""
348 os.path.join('LayoutTests', 'ChangeLog'),
352 self._assert_should_skip_without_warning(path,
353 is_checker_none=False,
357 class CheckerDispatcherCarriageReturnTest(unittest.TestCase):
358 def test_should_check_and_strip_carriage_returns(self):
363 'foo.vsprops': False,
366 dispatcher = CheckerDispatcher()
367 for file_path, expected_result in files.items():
368 self.assertEquals(dispatcher.should_check_and_strip_carriage_returns(file_path), expected_result, 'Checking: %s' % file_path)
371 class CheckerDispatcherDispatchTest(unittest.TestCase):
373 """Tests dispatch() method of CheckerDispatcher class."""
375 def dispatch(self, file_path):
376 """Call dispatch() with the given file path."""
377 dispatcher = CheckerDispatcher()
378 self.mock_handle_style_error = DefaultStyleErrorHandler('', None, None, [])
379 checker = dispatcher.dispatch(file_path,
380 self.mock_handle_style_error,
384 def assert_checker_none(self, file_path):
385 """Assert that the dispatched checker is None."""
386 checker = self.dispatch(file_path)
387 self.assertTrue(checker is None, 'Checking: "%s"' % file_path)
389 def assert_checker(self, file_path, expected_class):
390 """Assert the type of the dispatched checker."""
391 checker = self.dispatch(file_path)
392 got_class = checker.__class__
393 self.assertEquals(got_class, expected_class,
394 'For path "%(file_path)s" got %(got_class)s when '
395 "expecting %(expected_class)s."
396 % {"file_path": file_path,
397 "got_class": got_class,
398 "expected_class": expected_class})
400 def assert_checker_changelog(self, file_path):
401 """Assert that the dispatched checker is a ChangeLogChecker."""
402 self.assert_checker(file_path, ChangeLogChecker)
404 def assert_checker_cpp(self, file_path):
405 """Assert that the dispatched checker is a CppChecker."""
406 self.assert_checker(file_path, CppChecker)
408 def assert_checker_python(self, file_path):
409 """Assert that the dispatched checker is a PythonChecker."""
410 self.assert_checker(file_path, PythonChecker)
412 def assert_checker_text(self, file_path):
413 """Assert that the dispatched checker is a TextChecker."""
414 self.assert_checker(file_path, TextChecker)
416 def assert_checker_xml(self, file_path):
417 """Assert that the dispatched checker is a XMLChecker."""
418 self.assert_checker(file_path, XMLChecker)
420 def test_changelog_paths(self):
421 """Test paths that should be checked as ChangeLog."""
424 "ChangeLog-2009-06-16",
425 os.path.join("Source", "WebCore", "ChangeLog"),
429 self.assert_checker_changelog(path)
431 # Check checker attributes on a typical input.
432 file_path = "ChangeLog"
433 self.assert_checker_changelog(file_path)
434 checker = self.dispatch(file_path)
435 self.assertEquals(checker.file_path, file_path)
436 self.assertEquals(checker.handle_style_error,
437 self.mock_handle_style_error)
439 def test_cpp_paths(self):
440 """Test paths that should be checked as C++."""
449 self.assert_checker_cpp(path)
451 # Check checker attributes on a typical input.
454 file_path = file_base + "." + file_extension
455 self.assert_checker_cpp(file_path)
456 checker = self.dispatch(file_path)
457 self.assertEquals(checker.file_extension, file_extension)
458 self.assertEquals(checker.file_path, file_path)
459 self.assertEquals(checker.handle_style_error, self.mock_handle_style_error)
460 self.assertEquals(checker.min_confidence, 3)
461 # Check "-" for good measure.
464 file_path = file_base
465 self.assert_checker_cpp(file_path)
466 checker = self.dispatch(file_path)
467 self.assertEquals(checker.file_extension, file_extension)
468 self.assertEquals(checker.file_path, file_path)
470 def test_python_paths(self):
471 """Test paths that should be checked as Python."""
474 "Tools/Scripts/modules/text_style.py",
478 self.assert_checker_python(path)
480 # Check checker attributes on a typical input.
482 file_extension = "css"
483 file_path = file_base + "." + file_extension
484 self.assert_checker_text(file_path)
485 checker = self.dispatch(file_path)
486 self.assertEquals(checker.file_path, file_path)
487 self.assertEquals(checker.handle_style_error,
488 self.mock_handle_style_error)
490 def test_text_paths(self):
491 """Test paths that should be checked as text."""
517 os.path.join("Source", "WebCore", "inspector", "front-end", "inspector.js"),
518 os.path.join("Tools", "Scripts", "check-webkit-style"),
522 self.assert_checker_text(path)
524 # Check checker attributes on a typical input.
526 file_extension = "css"
527 file_path = file_base + "." + file_extension
528 self.assert_checker_text(file_path)
529 checker = self.dispatch(file_path)
530 self.assertEquals(checker.file_path, file_path)
531 self.assertEquals(checker.handle_style_error, self.mock_handle_style_error)
533 def test_xml_paths(self):
534 """Test paths that should be checked as XML."""
536 "Source/WebCore/WebCore.vcproj/WebCore.vcproj",
537 "WebKitLibraries/win/tools/vsprops/common.vsprops",
541 self.assert_checker_xml(path)
543 # Check checker attributes on a typical input.
545 file_extension = "vcproj"
546 file_path = file_base + "." + file_extension
547 self.assert_checker_xml(file_path)
548 checker = self.dispatch(file_path)
549 self.assertEquals(checker._handle_style_error,
550 self.mock_handle_style_error)
552 def test_none_paths(self):
553 """Test paths that have no file type.."""
556 "foo.asdf", # Non-sensical file extension.
562 self.assert_checker_none(path)
565 class StyleProcessorConfigurationTest(unittest.TestCase):
567 """Tests the StyleProcessorConfiguration class."""
570 self._error_messages = []
571 """The messages written to _mock_stderr_write() of this class."""
573 def _mock_stderr_write(self, message):
574 self._error_messages.append(message)
576 def _style_checker_configuration(self, output_format="vs7"):
577 """Return a StyleProcessorConfiguration instance for testing."""
578 base_rules = ["-whitespace", "+whitespace/tab"]
579 filter_configuration = FilterConfiguration(base_rules=base_rules)
581 return StyleProcessorConfiguration(
582 filter_configuration=filter_configuration,
583 max_reports_per_category={"whitespace/newline": 1},
585 output_format=output_format,
586 stderr_write=self._mock_stderr_write)
589 """Test the __init__() method."""
590 configuration = self._style_checker_configuration()
592 # Check that __init__ sets the "public" data attributes correctly.
593 self.assertEquals(configuration.max_reports_per_category,
594 {"whitespace/newline": 1})
595 self.assertEquals(configuration.stderr_write, self._mock_stderr_write)
596 self.assertEquals(configuration.min_confidence, 3)
598 def test_is_reportable(self):
599 """Test the is_reportable() method."""
600 config = self._style_checker_configuration()
602 self.assertTrue(config.is_reportable("whitespace/tab", 3, "foo.txt"))
604 # Test the confidence check code path by varying the confidence.
605 self.assertFalse(config.is_reportable("whitespace/tab", 2, "foo.txt"))
607 # Test the category check code path by varying the category.
608 self.assertFalse(config.is_reportable("whitespace/line", 4, "foo.txt"))
610 def _call_write_style_error(self, output_format):
611 config = self._style_checker_configuration(output_format=output_format)
612 config.write_style_error(category="whitespace/tab",
613 confidence_in_error=5,
618 def test_write_style_error_emacs(self):
619 """Test the write_style_error() method."""
620 self._call_write_style_error("emacs")
621 self.assertEquals(self._error_messages,
622 ["foo.h:100: message [whitespace/tab] [5]\n"])
624 def test_write_style_error_vs7(self):
625 """Test the write_style_error() method."""
626 self._call_write_style_error("vs7")
627 self.assertEquals(self._error_messages,
628 ["foo.h(100): message [whitespace/tab] [5]\n"])
631 class StyleProcessor_EndToEndTest(LoggingTestCase):
633 """Test the StyleProcessor class with an emphasis on end-to-end tests."""
636 LoggingTestCase.setUp(self)
639 def _mock_stderr_write(self, message):
640 """Save a message so it can later be asserted."""
641 self._messages.append(message)
644 """Test __init__ constructor."""
645 configuration = StyleProcessorConfiguration(
646 filter_configuration=FilterConfiguration(),
647 max_reports_per_category={},
650 stderr_write=self._mock_stderr_write)
651 processor = StyleProcessor(configuration)
653 self.assertEquals(processor.error_count, 0)
654 self.assertEquals(self._messages, [])
656 def test_process(self):
657 configuration = StyleProcessorConfiguration(
658 filter_configuration=FilterConfiguration(),
659 max_reports_per_category={},
662 stderr_write=self._mock_stderr_write)
663 processor = StyleProcessor(configuration)
665 processor.process(lines=['line1', 'Line with tab:\t'],
667 self.assertEquals(processor.error_count, 1)
668 expected_messages = ['foo.txt(2): Line contains tab character. '
669 '[whitespace/tab] [5]\n']
670 self.assertEquals(self._messages, expected_messages)
673 class StyleProcessor_CodeCoverageTest(LoggingTestCase):
675 """Test the StyleProcessor class with an emphasis on code coverage.
677 This class makes heavy use of mock objects.
681 class MockDispatchedChecker(object):
683 """A mock checker dispatched by the MockDispatcher."""
685 def __init__(self, file_path, min_confidence, style_error_handler):
686 self.file_path = file_path
687 self.min_confidence = min_confidence
688 self.style_error_handler = style_error_handler
690 def check(self, lines):
693 class MockDispatcher(object):
695 """A mock CheckerDispatcher class."""
698 self.dispatched_checker = None
700 def should_skip_with_warning(self, file_path):
701 return file_path.endswith('skip_with_warning.txt')
703 def should_skip_without_warning(self, file_path):
704 return file_path.endswith('skip_without_warning.txt')
706 def should_check_and_strip_carriage_returns(self, file_path):
707 return not file_path.endswith('carriage_returns_allowed.txt')
709 def dispatch(self, file_path, style_error_handler, min_confidence):
710 if file_path.endswith('do_not_process.txt'):
713 checker = StyleProcessor_CodeCoverageTest.MockDispatchedChecker(
718 # Save the dispatched checker so the current test case has a
719 # way to access and check it.
720 self.dispatched_checker = checker
725 LoggingTestCase.setUp(self)
726 # We can pass an error-message swallower here because error message
727 # output is tested instead in the end-to-end test case above.
728 configuration = StyleProcessorConfiguration(
729 filter_configuration=FilterConfiguration(),
730 max_reports_per_category={"whitespace/newline": 1},
733 stderr_write=self._swallow_stderr_message)
735 mock_carriage_checker_class = self._create_carriage_checker_class()
736 mock_dispatcher = self.MockDispatcher()
737 # We do not need to use a real incrementer here because error-count
738 # incrementing is tested instead in the end-to-end test case above.
739 mock_increment_error_count = self._do_nothing
741 processor = StyleProcessor(configuration=configuration,
742 mock_carriage_checker_class=mock_carriage_checker_class,
743 mock_dispatcher=mock_dispatcher,
744 mock_increment_error_count=mock_increment_error_count)
746 self._configuration = configuration
747 self._mock_dispatcher = mock_dispatcher
748 self._processor = processor
750 def _do_nothing(self):
751 # We provide this function so the caller can pass it to the
752 # StyleProcessor constructor. This lets us assert the equality of
753 # the DefaultStyleErrorHandler instance generated by the process()
754 # method with an expected instance.
757 def _swallow_stderr_message(self, message):
758 """Swallow a message passed to stderr.write()."""
759 # This is a mock stderr.write() for passing to the constructor
760 # of the StyleProcessorConfiguration class.
763 def _create_carriage_checker_class(self):
765 # Create a reference to self with a new name so its name does not
766 # conflict with the self introduced below.
769 class MockCarriageChecker(object):
771 """A mock carriage-return checker."""
773 def __init__(self, style_error_handler):
774 self.style_error_handler = style_error_handler
776 # This gives the current test case access to the
777 # instantiated carriage checker.
778 test_case.carriage_checker = self
780 def check(self, lines):
781 # Save the lines so the current test case has a way to access
787 return MockCarriageChecker
789 def test_should_process__skip_without_warning(self):
790 """Test should_process() for a skip-without-warning file."""
791 file_path = "foo/skip_without_warning.txt"
793 self.assertFalse(self._processor.should_process(file_path))
795 def test_should_process__skip_with_warning(self):
796 """Test should_process() for a skip-with-warning file."""
797 file_path = "foo/skip_with_warning.txt"
799 self.assertFalse(self._processor.should_process(file_path))
801 self.assertLog(['WARNING: File exempt from style guide. '
802 'Skipping: "foo/skip_with_warning.txt"\n'])
804 def test_should_process__true_result(self):
805 """Test should_process() for a file that should be processed."""
806 file_path = "foo/skip_process.txt"
808 self.assertTrue(self._processor.should_process(file_path))
810 def test_process__checker_dispatched(self):
811 """Test the process() method for a path with a dispatched checker."""
812 file_path = 'foo.txt'
813 lines = ['line1', 'line2']
816 expected_error_handler = DefaultStyleErrorHandler(
817 configuration=self._configuration,
819 increment_error_count=self._do_nothing,
820 line_numbers=line_numbers)
822 self._processor.process(lines=lines,
824 line_numbers=line_numbers)
826 # Check that the carriage-return checker was instantiated correctly
827 # and was passed lines correctly.
828 carriage_checker = self.carriage_checker
829 self.assertEquals(carriage_checker.style_error_handler,
830 expected_error_handler)
831 self.assertEquals(carriage_checker.lines, ['line1', 'line2'])
833 # Check that the style checker was dispatched correctly and was
834 # passed lines correctly.
835 checker = self._mock_dispatcher.dispatched_checker
836 self.assertEquals(checker.file_path, 'foo.txt')
837 self.assertEquals(checker.min_confidence, 3)
838 self.assertEquals(checker.style_error_handler, expected_error_handler)
840 self.assertEquals(checker.lines, ['line1', 'line2'])
842 def test_process__no_checker_dispatched(self):
843 """Test the process() method for a path with no dispatched checker."""
844 path = os.path.join('foo', 'do_not_process.txt')
845 self.assertRaises(AssertionError, self._processor.process,
846 lines=['line1', 'line2'], file_path=path,
849 def test_process__carriage_returns_not_stripped(self):
850 """Test that carriage returns aren't stripped from files that are allowed to contain them."""
851 file_path = 'carriage_returns_allowed.txt'
852 lines = ['line1\r', 'line2\r']
854 self._processor.process(lines=lines,
856 line_numbers=line_numbers)
857 # The carriage return checker should never have been invoked, and so
858 # should not have saved off any lines.
859 self.assertFalse(hasattr(self.carriage_checker, 'lines'))