Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(57)

Side by Side Diff: sky/tools/webkitpy/style/checker_unittest.py

Issue 675343003: Prune a bunch of webkitpy. (Closed) Base URL: git@github.com:domokit/mojo.git@master
Patch Set: Created 6 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « sky/tools/webkitpy/style/checker.py ('k') | sky/tools/webkitpy/style/checkers/__init__.py » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 # -*- coding: utf-8; -*-
2 #
3 # Copyright (C) 2009 Google Inc. All rights reserved.
4 # Copyright (C) 2009 Torch Mobile Inc.
5 # Copyright (C) 2009 Apple Inc. All rights reserved.
6 # Copyright (C) 2010 Chris Jerdonek (chris.jerdonek@gmail.com)
7 #
8 # Redistribution and use in source and binary forms, with or without
9 # modification, are permitted provided that the following conditions are
10 # met:
11 #
12 # * Redistributions of source code must retain the above copyright
13 # notice, this list of conditions and the following disclaimer.
14 # * Redistributions in binary form must reproduce the above
15 # copyright notice, this list of conditions and the following disclaimer
16 # in the documentation and/or other materials provided with the
17 # distribution.
18 # * Neither the name of Google Inc. nor the names of its
19 # contributors may be used to endorse or promote products derived from
20 # this software without specific prior written permission.
21 #
22 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
23 # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
24 # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
25 # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
26 # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
27 # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
28 # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
29 # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
30 # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
31 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
32 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33
34 """Unit tests for style.py."""
35
36 import logging
37 import os
38 import unittest
39
40 import checker as style
41 from webkitpy.common.system.logtesting import LogTesting, TestLogStream
42 from checker import _BASE_FILTER_RULES
43 from checker import _MAX_REPORTS_PER_CATEGORY
44 from checker import _PATH_RULES_SPECIFIER as PATH_RULES_SPECIFIER
45 from checker import _all_categories
46 from checker import check_webkit_style_configuration
47 from checker import check_webkit_style_parser
48 from checker import configure_logging
49 from checker import CheckerDispatcher
50 from checker import ProcessorBase
51 from checker import StyleProcessor
52 from checker import StyleProcessorConfiguration
53 from checkers.cpp import CppChecker
54 from checkers.jsonchecker import JSONChecker
55 from checkers.python import PythonChecker
56 from checkers.text import TextChecker
57 from checkers.xml import XMLChecker
58 from error_handlers import DefaultStyleErrorHandler
59 from filter import validate_filter_rules
60 from filter import FilterConfiguration
61 from optparser import ArgumentParser
62 from optparser import CommandOptionValues
63 from webkitpy.common.system.logtesting import LoggingTestCase
64 from webkitpy.style.filereader import TextFileReader
65
66
67 class ConfigureLoggingTestBase(unittest.TestCase):
68
69 """Base class for testing configure_logging().
70
71 Sub-classes should implement:
72
73 is_verbose: The is_verbose value to pass to configure_logging().
74
75 """
76
77 def setUp(self):
78 is_verbose = self.is_verbose
79
80 log_stream = TestLogStream(self)
81
82 # Use a logger other than the root logger or one prefixed with
83 # webkit so as not to conflict with test-webkitpy logging.
84 logger = logging.getLogger("unittest")
85
86 # Configure the test logger not to pass messages along to the
87 # root logger. This prevents test messages from being
88 # propagated to loggers used by test-webkitpy logging (e.g.
89 # the root logger).
90 logger.propagate = False
91
92 self._handlers = configure_logging(stream=log_stream, logger=logger,
93 is_verbose=is_verbose)
94 self._log = logger
95 self._log_stream = log_stream
96
97 def tearDown(self):
98 """Reset logging to its original state.
99
100 This method ensures that the logging configuration set up
101 for a unit test does not affect logging in other unit tests.
102
103 """
104 logger = self._log
105 for handler in self._handlers:
106 logger.removeHandler(handler)
107
108 def assert_log_messages(self, messages):
109 """Assert that the logged messages equal the given messages."""
110 self._log_stream.assertMessages(messages)
111
112
113 class ConfigureLoggingTest(ConfigureLoggingTestBase):
114
115 """Tests the configure_logging() function."""
116
117 is_verbose = False
118
119 def test_warning_message(self):
120 self._log.warn("test message")
121 self.assert_log_messages(["WARNING: test message\n"])
122
123 def test_below_warning_message(self):
124 # We test the boundary case of a logging level equal to 29.
125 # In practice, we will probably only be calling log.info(),
126 # which corresponds to a logging level of 20.
127 level = logging.WARNING - 1 # Equals 29.
128 self._log.log(level, "test message")
129 self.assert_log_messages(["test message\n"])
130
131 def test_debug_message(self):
132 self._log.debug("test message")
133 self.assert_log_messages([])
134
135 def test_two_messages(self):
136 self._log.info("message1")
137 self._log.info("message2")
138 self.assert_log_messages(["message1\n", "message2\n"])
139
140
141 class ConfigureLoggingVerboseTest(ConfigureLoggingTestBase):
142
143 """Tests the configure_logging() function with is_verbose True."""
144
145 is_verbose = True
146
147 def test_debug_message(self):
148 self._log.debug("test message")
149 self.assert_log_messages(["unittest: DEBUG test message\n"])
150
151
152 class GlobalVariablesTest(unittest.TestCase):
153
154 """Tests validity of the global variables."""
155
156 def _all_categories(self):
157 return _all_categories()
158
159 def defaults(self):
160 return style._check_webkit_style_defaults()
161
162 def test_webkit_base_filter_rules(self):
163 base_filter_rules = _BASE_FILTER_RULES
164 defaults = self.defaults()
165 already_seen = []
166 validate_filter_rules(base_filter_rules, self._all_categories())
167 # Also do some additional checks.
168 for rule in base_filter_rules:
169 # Check no leading or trailing white space.
170 self.assertEqual(rule, rule.strip())
171 # All categories are on by default, so defaults should
172 # begin with -.
173 self.assertTrue(rule.startswith('-'))
174 # Check no rule occurs twice.
175 self.assertNotIn(rule, already_seen)
176 already_seen.append(rule)
177
178 def test_defaults(self):
179 """Check that default arguments are valid."""
180 default_options = self.defaults()
181
182 # FIXME: We should not need to call parse() to determine
183 # whether the default arguments are valid.
184 parser = ArgumentParser(all_categories=self._all_categories(),
185 base_filter_rules=[],
186 default_options=default_options)
187 # No need to test the return value here since we test parse()
188 # on valid arguments elsewhere.
189 #
190 # The default options are valid: no error or SystemExit.
191 parser.parse(args=[])
192
193 def test_path_rules_specifier(self):
194 all_categories = self._all_categories()
195 for (sub_paths, path_rules) in PATH_RULES_SPECIFIER:
196 validate_filter_rules(path_rules, self._all_categories())
197
198 config = FilterConfiguration(path_specific=PATH_RULES_SPECIFIER)
199
200 def assertCheck(path, category):
201 """Assert that the given category should be checked."""
202 message = ('Should check category "%s" for path "%s".'
203 % (category, path))
204 self.assertTrue(config.should_check(category, path))
205
206 def assertNoCheck(path, category):
207 """Assert that the given category should not be checked."""
208 message = ('Should not check category "%s" for path "%s".'
209 % (category, path))
210 self.assertFalse(config.should_check(category, path), message)
211
212 assertCheck("random_path.cpp",
213 "build/include")
214 assertCheck("random_path.cpp",
215 "readability/naming")
216 assertNoCheck("Source/core/css/CSSParser-in.cpp",
217 "readability/naming")
218
219 # Third-party Python code: webkitpy/thirdparty
220 path = "Tools/Scripts/webkitpy/thirdparty/mock.py"
221 assertNoCheck(path, "build/include")
222 assertNoCheck(path, "pep8/E401") # A random pep8 category.
223 assertCheck(path, "pep8/W191")
224 assertCheck(path, "pep8/W291")
225 assertCheck(path, "whitespace/carriage_return")
226
227 def test_max_reports_per_category(self):
228 """Check that _MAX_REPORTS_PER_CATEGORY is valid."""
229 all_categories = self._all_categories()
230 for category in _MAX_REPORTS_PER_CATEGORY.iterkeys():
231 self.assertIn(category, all_categories,
232 'Key "%s" is not a category' % category)
233
234
235 class CheckWebKitStyleFunctionTest(unittest.TestCase):
236
237 """Tests the functions with names of the form check_webkit_style_*."""
238
239 def test_check_webkit_style_configuration(self):
240 # Exercise the code path to make sure the function does not error out.
241 option_values = CommandOptionValues()
242 configuration = check_webkit_style_configuration(option_values)
243
244 def test_check_webkit_style_parser(self):
245 # Exercise the code path to make sure the function does not error out.
246 parser = check_webkit_style_parser()
247
248
249 class CheckerDispatcherSkipTest(unittest.TestCase):
250
251 """Tests the "should skip" methods of the CheckerDispatcher class."""
252
253 def setUp(self):
254 self._dispatcher = CheckerDispatcher()
255
256 def test_should_skip_with_warning(self):
257 """Test should_skip_with_warning()."""
258 # Check skipped files.
259 paths_to_skip = [
260 "Source/WebKit/gtk/tests/testatk.c",
261 "Source/WebKit2/UIProcess/API/gtk/webkit2.h",
262 "Source/WebKit2/UIProcess/API/gtk/WebKitWebView.h",
263 "Source/WebKit2/UIProcess/API/gtk/WebKitLoader.h",
264 ]
265
266 for path in paths_to_skip:
267 self.assertTrue(self._dispatcher.should_skip_with_warning(path),
268 "Checking: " + path)
269
270 # Verify that some files are not skipped.
271 paths_not_to_skip = [
272 "foo.txt",
273 "Source/WebKit2/UIProcess/API/gtk/HelperClass.cpp",
274 "Source/WebKit2/UIProcess/API/gtk/HelperClass.h",
275 "Source/WebKit2/UIProcess/API/gtk/WebKitWebView.cpp",
276 "Source/WebKit2/UIProcess/API/gtk/WebKitWebViewPrivate.h",
277 "Source/WebKit2/UIProcess/API/gtk/tests/WebViewTest.cpp",
278 "Source/WebKit2/UIProcess/API/gtk/tests/WebViewTest.h",
279 ]
280
281 for path in paths_not_to_skip:
282 self.assertFalse(self._dispatcher.should_skip_with_warning(path))
283
284 def _assert_should_skip_without_warning(self, path, is_checker_none,
285 expected):
286 # Check the file type before asserting the return value.
287 checker = self._dispatcher.dispatch(file_path=path,
288 handle_style_error=None,
289 min_confidence=3)
290 message = 'while checking: %s' % path
291 self.assertEqual(checker is None, is_checker_none, message)
292 self.assertEqual(self._dispatcher.should_skip_without_warning(path),
293 expected, message)
294
295 def test_should_skip_without_warning__true(self):
296 """Test should_skip_without_warning() for True return values."""
297 # Check a file with NONE file type.
298 path = 'foo.asdf' # Non-sensical file extension.
299 self._assert_should_skip_without_warning(path,
300 is_checker_none=True,
301 expected=True)
302
303 # Check files with non-NONE file type. These examples must be
304 # drawn from the _SKIPPED_FILES_WITHOUT_WARNING configuration
305 # variable.
306 path = os.path.join('tests', 'foo.txt')
307 self._assert_should_skip_without_warning(path,
308 is_checker_none=False,
309 expected=True)
310
311 def test_should_skip_without_warning__false(self):
312 """Test should_skip_without_warning() for False return values."""
313 paths = ['foo.txt',
314 os.path.join('tests', 'TestExpectations'),
315 ]
316
317 for path in paths:
318 self._assert_should_skip_without_warning(path,
319 is_checker_none=False,
320 expected=False)
321
322
323 class CheckerDispatcherCarriageReturnTest(unittest.TestCase):
324 def test_should_check_and_strip_carriage_returns(self):
325 files = {
326 'foo.txt': True,
327 'foo.cpp': True,
328 'foo.vcproj': False,
329 'foo.vsprops': False,
330 }
331
332 dispatcher = CheckerDispatcher()
333 for file_path, expected_result in files.items():
334 self.assertEqual(dispatcher.should_check_and_strip_carriage_returns( file_path), expected_result, 'Checking: %s' % file_path)
335
336
337 class CheckerDispatcherDispatchTest(unittest.TestCase):
338
339 """Tests dispatch() method of CheckerDispatcher class."""
340
341 def dispatch(self, file_path):
342 """Call dispatch() with the given file path."""
343 dispatcher = CheckerDispatcher()
344 self.mock_handle_style_error = DefaultStyleErrorHandler('', None, None, [])
345 checker = dispatcher.dispatch(file_path,
346 self.mock_handle_style_error,
347 min_confidence=3)
348 return checker
349
350 def assert_checker_none(self, file_path):
351 """Assert that the dispatched checker is None."""
352 checker = self.dispatch(file_path)
353 self.assertIsNone(checker, 'Checking: "%s"' % file_path)
354
355 def assert_checker(self, file_path, expected_class):
356 """Assert the type of the dispatched checker."""
357 checker = self.dispatch(file_path)
358 got_class = checker.__class__
359 self.assertEqual(got_class, expected_class,
360 'For path "%(file_path)s" got %(got_class)s when '
361 "expecting %(expected_class)s."
362 % {"file_path": file_path,
363 "got_class": got_class,
364 "expected_class": expected_class})
365
366 def assert_checker_cpp(self, file_path):
367 """Assert that the dispatched checker is a CppChecker."""
368 self.assert_checker(file_path, CppChecker)
369
370 def assert_checker_json(self, file_path):
371 """Assert that the dispatched checker is a JSONChecker."""
372 self.assert_checker(file_path, JSONChecker)
373
374 def assert_checker_python(self, file_path):
375 """Assert that the dispatched checker is a PythonChecker."""
376 self.assert_checker(file_path, PythonChecker)
377
378 def assert_checker_text(self, file_path):
379 """Assert that the dispatched checker is a TextChecker."""
380 self.assert_checker(file_path, TextChecker)
381
382 def assert_checker_xml(self, file_path):
383 """Assert that the dispatched checker is a XMLChecker."""
384 self.assert_checker(file_path, XMLChecker)
385
386 def test_cpp_paths(self):
387 """Test paths that should be checked as C++."""
388 paths = [
389 "-",
390 "foo.c",
391 "foo.cpp",
392 "foo.h",
393 ]
394
395 for path in paths:
396 self.assert_checker_cpp(path)
397
398 # Check checker attributes on a typical input.
399 file_base = "foo"
400 file_extension = "c"
401 file_path = file_base + "." + file_extension
402 self.assert_checker_cpp(file_path)
403 checker = self.dispatch(file_path)
404 self.assertEqual(checker.file_extension, file_extension)
405 self.assertEqual(checker.file_path, file_path)
406 self.assertEqual(checker.handle_style_error, self.mock_handle_style_erro r)
407 self.assertEqual(checker.min_confidence, 3)
408 # Check "-" for good measure.
409 file_base = "-"
410 file_extension = ""
411 file_path = file_base
412 self.assert_checker_cpp(file_path)
413 checker = self.dispatch(file_path)
414 self.assertEqual(checker.file_extension, file_extension)
415 self.assertEqual(checker.file_path, file_path)
416
417 def test_json_paths(self):
418 """Test paths that should be checked as JSON."""
419 paths = [
420 "Source/WebCore/inspector/Inspector.json",
421 "Tools/BuildSlaveSupport/build.webkit.org-config/config.json",
422 ]
423
424 for path in paths:
425 self.assert_checker_json(path)
426
427 # Check checker attributes on a typical input.
428 file_base = "foo"
429 file_extension = "json"
430 file_path = file_base + "." + file_extension
431 self.assert_checker_json(file_path)
432 checker = self.dispatch(file_path)
433 self.assertEqual(checker._handle_style_error,
434 self.mock_handle_style_error)
435
436 def test_python_paths(self):
437 """Test paths that should be checked as Python."""
438 paths = [
439 "foo.py",
440 "Tools/Scripts/modules/text_style.py",
441 ]
442
443 for path in paths:
444 self.assert_checker_python(path)
445
446 # Check checker attributes on a typical input.
447 file_base = "foo"
448 file_extension = "css"
449 file_path = file_base + "." + file_extension
450 self.assert_checker_text(file_path)
451 checker = self.dispatch(file_path)
452 self.assertEqual(checker.file_path, file_path)
453 self.assertEqual(checker.handle_style_error,
454 self.mock_handle_style_error)
455
456 def test_text_paths(self):
457 """Test paths that should be checked as text."""
458 paths = [
459 "foo.cc",
460 "foo.cgi",
461 "foo.css",
462 "foo.gyp",
463 "foo.gypi",
464 "foo.html",
465 "foo.idl",
466 "foo.in",
467 "foo.js",
468 "foo.mm",
469 "foo.php",
470 "foo.pl",
471 "foo.pm",
472 "foo.rb",
473 "foo.sh",
474 "foo.txt",
475 "foo.xhtml",
476 "foo.y",
477 os.path.join("Source", "WebCore", "inspector", "front-end", "Main.js" ),
478 os.path.join("Tools", "Scripts", "check-webkit-style"),
479 ]
480
481 for path in paths:
482 self.assert_checker_text(path)
483
484 # Check checker attributes on a typical input.
485 file_base = "foo"
486 file_extension = "css"
487 file_path = file_base + "." + file_extension
488 self.assert_checker_text(file_path)
489 checker = self.dispatch(file_path)
490 self.assertEqual(checker.file_path, file_path)
491 self.assertEqual(checker.handle_style_error, self.mock_handle_style_erro r)
492
493 def test_xml_paths(self):
494 """Test paths that should be checked as XML."""
495 paths = [
496 "Source/WebCore/WebCore.vcproj/WebCore.vcproj",
497 "WebKitLibraries/win/tools/vsprops/common.vsprops",
498 ]
499
500 for path in paths:
501 self.assert_checker_xml(path)
502
503 # Check checker attributes on a typical input.
504 file_base = "foo"
505 file_extension = "vcproj"
506 file_path = file_base + "." + file_extension
507 self.assert_checker_xml(file_path)
508 checker = self.dispatch(file_path)
509 self.assertEqual(checker._handle_style_error,
510 self.mock_handle_style_error)
511
512 def test_none_paths(self):
513 """Test paths that have no file type.."""
514 paths = [
515 "Makefile",
516 "foo.asdf", # Non-sensical file extension.
517 "foo.exe",
518 ]
519
520 for path in paths:
521 self.assert_checker_none(path)
522
523
524 class StyleProcessorConfigurationTest(unittest.TestCase):
525
526 """Tests the StyleProcessorConfiguration class."""
527
528 def setUp(self):
529 self._error_messages = []
530 """The messages written to _mock_stderr_write() of this class."""
531
532 def _mock_stderr_write(self, message):
533 self._error_messages.append(message)
534
535 def _style_checker_configuration(self, output_format="vs7"):
536 """Return a StyleProcessorConfiguration instance for testing."""
537 base_rules = ["-whitespace", "+whitespace/tab"]
538 filter_configuration = FilterConfiguration(base_rules=base_rules)
539
540 return StyleProcessorConfiguration(
541 filter_configuration=filter_configuration,
542 max_reports_per_category={"whitespace/newline": 1},
543 min_confidence=3,
544 output_format=output_format,
545 stderr_write=self._mock_stderr_write)
546
547 def test_init(self):
548 """Test the __init__() method."""
549 configuration = self._style_checker_configuration()
550
551 # Check that __init__ sets the "public" data attributes correctly.
552 self.assertEqual(configuration.max_reports_per_category,
553 {"whitespace/newline": 1})
554 self.assertEqual(configuration.stderr_write, self._mock_stderr_write)
555 self.assertEqual(configuration.min_confidence, 3)
556
557 def test_is_reportable(self):
558 """Test the is_reportable() method."""
559 config = self._style_checker_configuration()
560
561 self.assertTrue(config.is_reportable("whitespace/tab", 3, "foo.txt"))
562
563 # Test the confidence check code path by varying the confidence.
564 self.assertFalse(config.is_reportable("whitespace/tab", 2, "foo.txt"))
565
566 # Test the category check code path by varying the category.
567 self.assertFalse(config.is_reportable("whitespace/line", 4, "foo.txt"))
568
569 def _call_write_style_error(self, output_format):
570 config = self._style_checker_configuration(output_format=output_format)
571 config.write_style_error(category="whitespace/tab",
572 confidence_in_error=5,
573 file_path="foo.h",
574 line_number=100,
575 message="message")
576
577 def test_write_style_error_emacs(self):
578 """Test the write_style_error() method."""
579 self._call_write_style_error("emacs")
580 self.assertEqual(self._error_messages,
581 ["foo.h:100: message [whitespace/tab] [5]\n"])
582
583 def test_write_style_error_vs7(self):
584 """Test the write_style_error() method."""
585 self._call_write_style_error("vs7")
586 self.assertEqual(self._error_messages,
587 ["foo.h(100): message [whitespace/tab] [5]\n"])
588
589
590 class StyleProcessor_EndToEndTest(LoggingTestCase):
591
592 """Test the StyleProcessor class with an emphasis on end-to-end tests."""
593
594 def setUp(self):
595 LoggingTestCase.setUp(self)
596 self._messages = []
597
598 def _mock_stderr_write(self, message):
599 """Save a message so it can later be asserted."""
600 self._messages.append(message)
601
602 def test_init(self):
603 """Test __init__ constructor."""
604 configuration = StyleProcessorConfiguration(
605 filter_configuration=FilterConfiguration(),
606 max_reports_per_category={},
607 min_confidence=3,
608 output_format="vs7",
609 stderr_write=self._mock_stderr_write)
610 processor = StyleProcessor(configuration)
611
612 self.assertEqual(processor.error_count, 0)
613 self.assertEqual(self._messages, [])
614
615 def test_process(self):
616 configuration = StyleProcessorConfiguration(
617 filter_configuration=FilterConfiguration(),
618 max_reports_per_category={},
619 min_confidence=3,
620 output_format="vs7",
621 stderr_write=self._mock_stderr_write)
622 processor = StyleProcessor(configuration)
623
624 processor.process(lines=['line1', 'Line with tab:\t'],
625 file_path='foo.txt')
626 self.assertEqual(processor.error_count, 1)
627 expected_messages = ['foo.txt(2): Line contains tab character. '
628 '[whitespace/tab] [5]\n']
629 self.assertEqual(self._messages, expected_messages)
630
631
632 class StyleProcessor_CodeCoverageTest(LoggingTestCase):
633
634 """Test the StyleProcessor class with an emphasis on code coverage.
635
636 This class makes heavy use of mock objects.
637
638 """
639
640 class MockDispatchedChecker(object):
641
642 """A mock checker dispatched by the MockDispatcher."""
643
644 def __init__(self, file_path, min_confidence, style_error_handler):
645 self.file_path = file_path
646 self.min_confidence = min_confidence
647 self.style_error_handler = style_error_handler
648
649 def check(self, lines):
650 self.lines = lines
651
652 class MockDispatcher(object):
653
654 """A mock CheckerDispatcher class."""
655
656 def __init__(self):
657 self.dispatched_checker = None
658
659 def should_skip_with_warning(self, file_path):
660 return file_path.endswith('skip_with_warning.txt')
661
662 def should_skip_without_warning(self, file_path):
663 return file_path.endswith('skip_without_warning.txt')
664
665 def should_check_and_strip_carriage_returns(self, file_path):
666 return not file_path.endswith('carriage_returns_allowed.txt')
667
668 def dispatch(self, file_path, style_error_handler, min_confidence):
669 if file_path.endswith('do_not_process.txt'):
670 return None
671
672 checker = StyleProcessor_CodeCoverageTest.MockDispatchedChecker(
673 file_path,
674 min_confidence,
675 style_error_handler)
676
677 # Save the dispatched checker so the current test case has a
678 # way to access and check it.
679 self.dispatched_checker = checker
680
681 return checker
682
683 def setUp(self):
684 LoggingTestCase.setUp(self)
685 # We can pass an error-message swallower here because error message
686 # output is tested instead in the end-to-end test case above.
687 configuration = StyleProcessorConfiguration(
688 filter_configuration=FilterConfiguration(),
689 max_reports_per_category={"whitespace/newline": 1},
690 min_confidence=3,
691 output_format="vs7",
692 stderr_write=self._swallow_stderr_message)
693
694 mock_carriage_checker_class = self._create_carriage_checker_class()
695 mock_dispatcher = self.MockDispatcher()
696 # We do not need to use a real incrementer here because error-count
697 # incrementing is tested instead in the end-to-end test case above.
698 mock_increment_error_count = self._do_nothing
699
700 processor = StyleProcessor(configuration=configuration,
701 mock_carriage_checker_class=mock_carriage_checker_class,
702 mock_dispatcher=mock_dispatcher,
703 mock_increment_error_count=mock_increment_error_count)
704
705 self._configuration = configuration
706 self._mock_dispatcher = mock_dispatcher
707 self._processor = processor
708
709 def _do_nothing(self):
710 # We provide this function so the caller can pass it to the
711 # StyleProcessor constructor. This lets us assert the equality of
712 # the DefaultStyleErrorHandler instance generated by the process()
713 # method with an expected instance.
714 pass
715
716 def _swallow_stderr_message(self, message):
717 """Swallow a message passed to stderr.write()."""
718 # This is a mock stderr.write() for passing to the constructor
719 # of the StyleProcessorConfiguration class.
720 pass
721
722 def _create_carriage_checker_class(self):
723
724 # Create a reference to self with a new name so its name does not
725 # conflict with the self introduced below.
726 test_case = self
727
728 class MockCarriageChecker(object):
729
730 """A mock carriage-return checker."""
731
732 def __init__(self, style_error_handler):
733 self.style_error_handler = style_error_handler
734
735 # This gives the current test case access to the
736 # instantiated carriage checker.
737 test_case.carriage_checker = self
738
739 def check(self, lines):
740 # Save the lines so the current test case has a way to access
741 # and check them.
742 self.lines = lines
743
744 return lines
745
746 return MockCarriageChecker
747
748 def test_should_process__skip_without_warning(self):
749 """Test should_process() for a skip-without-warning file."""
750 file_path = "foo/skip_without_warning.txt"
751
752 self.assertFalse(self._processor.should_process(file_path))
753
754 def test_should_process__skip_with_warning(self):
755 """Test should_process() for a skip-with-warning file."""
756 file_path = "foo/skip_with_warning.txt"
757
758 self.assertFalse(self._processor.should_process(file_path))
759
760 self.assertLog(['WARNING: File exempt from style guide. '
761 'Skipping: "foo/skip_with_warning.txt"\n'])
762
763 def test_should_process__true_result(self):
764 """Test should_process() for a file that should be processed."""
765 file_path = "foo/skip_process.txt"
766
767 self.assertTrue(self._processor.should_process(file_path))
768
769 def test_process__checker_dispatched(self):
770 """Test the process() method for a path with a dispatched checker."""
771 file_path = 'foo.txt'
772 lines = ['line1', 'line2']
773 line_numbers = [100]
774
775 expected_error_handler = DefaultStyleErrorHandler(
776 configuration=self._configuration,
777 file_path=file_path,
778 increment_error_count=self._do_nothing,
779 line_numbers=line_numbers)
780
781 self._processor.process(lines=lines,
782 file_path=file_path,
783 line_numbers=line_numbers)
784
785 # Check that the carriage-return checker was instantiated correctly
786 # and was passed lines correctly.
787 carriage_checker = self.carriage_checker
788 self.assertEqual(carriage_checker.style_error_handler,
789 expected_error_handler)
790 self.assertEqual(carriage_checker.lines, ['line1', 'line2'])
791
792 # Check that the style checker was dispatched correctly and was
793 # passed lines correctly.
794 checker = self._mock_dispatcher.dispatched_checker
795 self.assertEqual(checker.file_path, 'foo.txt')
796 self.assertEqual(checker.min_confidence, 3)
797 self.assertEqual(checker.style_error_handler, expected_error_handler)
798
799 self.assertEqual(checker.lines, ['line1', 'line2'])
800
801 def test_process__no_checker_dispatched(self):
802 """Test the process() method for a path with no dispatched checker."""
803 path = os.path.join('foo', 'do_not_process.txt')
804 self.assertRaises(AssertionError, self._processor.process,
805 lines=['line1', 'line2'], file_path=path,
806 line_numbers=[100])
807
808 def test_process__carriage_returns_not_stripped(self):
809 """Test that carriage returns aren't stripped from files that are allowe d to contain them."""
810 file_path = 'carriage_returns_allowed.txt'
811 lines = ['line1\r', 'line2\r']
812 line_numbers = [100]
813 self._processor.process(lines=lines,
814 file_path=file_path,
815 line_numbers=line_numbers)
816 # The carriage return checker should never have been invoked, and so
817 # should not have saved off any lines.
818 self.assertFalse(hasattr(self.carriage_checker, 'lines'))
OLDNEW
« no previous file with comments | « sky/tools/webkitpy/style/checker.py ('k') | sky/tools/webkitpy/style/checkers/__init__.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698