1 # Copyright (C) 2010 Chris Jerdonek (cjerdonek (at] webkit.org) 2 # 3 # Redistribution and use in source and binary forms, with or without 4 # modification, are permitted provided that the following conditions 5 # are met: 6 # 1. Redistributions of source code must retain the above copyright 7 # notice, this list of conditions and the following disclaimer. 8 # 2. Redistributions in binary form must reproduce the above copyright 9 # notice, this list of conditions and the following disclaimer in the 10 # documentation and/or other materials provided with the distribution. 11 # 12 # THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND ANY 13 # EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 14 # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 15 # DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY 16 # DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 17 # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 18 # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 19 # ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 20 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 21 # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 22 23 """Unit tests for error_handlers.py.""" 24 25 import unittest 26 27 from checker import StyleProcessorConfiguration 28 from error_handlers import DefaultStyleErrorHandler 29 from filter import FilterConfiguration 30 31 32 class DefaultStyleErrorHandlerTest(unittest.TestCase): 33 34 """Tests the DefaultStyleErrorHandler class.""" 35 36 def setUp(self): 37 self._error_messages = [] 38 self._error_count = 0 39 40 _category = "whitespace/tab" 41 """The category name for the tests in this class.""" 42 43 _file_path = "foo.h" 44 """The file path for the tests in this class.""" 45 46 def _mock_increment_error_count(self): 47 self._error_count += 1 48 49 def _mock_stderr_write(self, message): 50 self._error_messages.append(message) 51 52 def _style_checker_configuration(self): 53 """Return a StyleProcessorConfiguration instance for testing.""" 54 base_rules = ["-whitespace", "+whitespace/tab"] 55 filter_configuration = FilterConfiguration(base_rules=base_rules) 56 57 return StyleProcessorConfiguration( 58 filter_configuration=filter_configuration, 59 max_reports_per_category={"whitespace/tab": 2}, 60 min_confidence=3, 61 output_format="vs7", 62 stderr_write=self._mock_stderr_write) 63 64 def _error_handler(self, configuration, line_numbers=None): 65 return DefaultStyleErrorHandler(configuration=configuration, 66 file_path=self._file_path, 67 increment_error_count=self._mock_increment_error_count, 68 line_numbers=line_numbers) 69 70 def _check_initialized(self): 71 """Check that count and error messages are initialized.""" 72 self.assertEqual(0, self._error_count) 73 self.assertEqual(0, len(self._error_messages)) 74 75 def _call_error_handler(self, handle_error, confidence, line_number=100): 76 """Call the given error handler with a test error.""" 77 handle_error(line_number=line_number, 78 category=self._category, 79 confidence=confidence, 80 message="message") 81 82 def test_eq__true_return_value(self): 83 """Test the __eq__() method for the return value of True.""" 84 handler1 = self._error_handler(configuration=None) 85 handler2 = self._error_handler(configuration=None) 86 87 self.assertTrue(handler1.__eq__(handler2)) 88 89 def test_eq__false_return_value(self): 90 """Test the __eq__() method for the return value of False.""" 91 def make_handler(configuration=self._style_checker_configuration(), 92 file_path='foo.txt', increment_error_count=lambda: True, 93 line_numbers=[100]): 94 return DefaultStyleErrorHandler(configuration=configuration, 95 file_path=file_path, 96 increment_error_count=increment_error_count, 97 line_numbers=line_numbers) 98 99 handler = make_handler() 100 101 # Establish a baseline for our comparisons below. 102 self.assertTrue(handler.__eq__(make_handler())) 103 104 # Verify that a difference in any argument causes equality to fail. 105 self.assertFalse(handler.__eq__(make_handler(configuration=None))) 106 self.assertFalse(handler.__eq__(make_handler(file_path='bar.txt'))) 107 self.assertFalse(handler.__eq__(make_handler(increment_error_count=None))) 108 self.assertFalse(handler.__eq__(make_handler(line_numbers=[50]))) 109 110 def test_ne(self): 111 """Test the __ne__() method.""" 112 # By default, __ne__ always returns true on different objects. 113 # Thus, check just the distinguishing case to verify that the 114 # code defines __ne__. 115 handler1 = self._error_handler(configuration=None) 116 handler2 = self._error_handler(configuration=None) 117 118 self.assertFalse(handler1.__ne__(handler2)) 119 120 def test_non_reportable_error(self): 121 """Test __call__() with a non-reportable error.""" 122 self._check_initialized() 123 configuration = self._style_checker_configuration() 124 125 confidence = 1 126 # Confirm the error is not reportable. 127 self.assertFalse(configuration.is_reportable(self._category, 128 confidence, 129 self._file_path)) 130 error_handler = self._error_handler(configuration) 131 self._call_error_handler(error_handler, confidence) 132 133 self.assertEqual(0, self._error_count) 134 self.assertEqual([], self._error_messages) 135 136 # Also serves as a reportable error test. 137 def test_max_reports_per_category(self): 138 """Test error report suppression in __call__() method.""" 139 self._check_initialized() 140 configuration = self._style_checker_configuration() 141 error_handler = self._error_handler(configuration) 142 143 confidence = 5 144 145 # First call: usual reporting. 146 self._call_error_handler(error_handler, confidence) 147 self.assertEqual(1, self._error_count) 148 self.assertEqual(1, len(self._error_messages)) 149 self.assertEqual(self._error_messages, 150 ["foo.h(100): message [whitespace/tab] [5]\n"]) 151 152 # Second call: suppression message reported. 153 self._call_error_handler(error_handler, confidence) 154 # The "Suppressing further..." message counts as an additional 155 # message (but not as an addition to the error count). 156 self.assertEqual(2, self._error_count) 157 self.assertEqual(3, len(self._error_messages)) 158 self.assertEqual(self._error_messages[-2], 159 "foo.h(100): message [whitespace/tab] [5]\n") 160 self.assertEqual(self._error_messages[-1], 161 "Suppressing further [whitespace/tab] reports " 162 "for this file.\n") 163 164 # Third call: no report. 165 self._call_error_handler(error_handler, confidence) 166 self.assertEqual(3, self._error_count) 167 self.assertEqual(3, len(self._error_messages)) 168 169 def test_line_numbers(self): 170 """Test the line_numbers parameter.""" 171 self._check_initialized() 172 configuration = self._style_checker_configuration() 173 error_handler = self._error_handler(configuration, 174 line_numbers=[50]) 175 confidence = 5 176 177 # Error on non-modified line: no error. 178 self._call_error_handler(error_handler, confidence, line_number=60) 179 self.assertEqual(0, self._error_count) 180 self.assertEqual([], self._error_messages) 181 182 # Error on modified line: error. 183 self._call_error_handler(error_handler, confidence, line_number=50) 184 self.assertEqual(1, self._error_count) 185 self.assertEqual(self._error_messages, 186 ["foo.h(50): message [whitespace/tab] [5]\n"]) 187 188 # Error on non-modified line after turning off line filtering: error. 189 error_handler.turn_off_line_filtering() 190 self._call_error_handler(error_handler, confidence, line_number=60) 191 self.assertEqual(2, self._error_count) 192 self.assertEqual(self._error_messages, 193 ['foo.h(50): message [whitespace/tab] [5]\n', 194 'foo.h(60): message [whitespace/tab] [5]\n', 195 'Suppressing further [whitespace/tab] reports for this file.\n']) 196