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 26 import unittest 27 28 from checker import StyleProcessorConfiguration 29 from error_handlers import DefaultStyleErrorHandler 30 from filter import FilterConfiguration 31 32 33 class DefaultStyleErrorHandlerTest(unittest.TestCase): 34 35 """Tests the DefaultStyleErrorHandler class.""" 36 37 def setUp(self): 38 self._error_messages = [] 39 self._error_count = 0 40 41 _category = "whitespace/tab" 42 """The category name for the tests in this class.""" 43 44 _file_path = "foo.h" 45 """The file path for the tests in this class.""" 46 47 def _mock_increment_error_count(self): 48 self._error_count += 1 49 50 def _mock_stderr_write(self, message): 51 self._error_messages.append(message) 52 53 def _style_checker_configuration(self): 54 """Return a StyleProcessorConfiguration instance for testing.""" 55 base_rules = ["-whitespace", "+whitespace/tab"] 56 filter_configuration = FilterConfiguration(base_rules=base_rules) 57 58 return StyleProcessorConfiguration( 59 filter_configuration=filter_configuration, 60 max_reports_per_category={"whitespace/tab": 2}, 61 min_confidence=3, 62 output_format="vs7", 63 stderr_write=self._mock_stderr_write) 64 65 def _error_handler(self, configuration, line_numbers=None): 66 return DefaultStyleErrorHandler(configuration=configuration, 67 file_path=self._file_path, 68 increment_error_count=self._mock_increment_error_count, 69 line_numbers=line_numbers) 70 71 def _check_initialized(self): 72 """Check that count and error messages are initialized.""" 73 self.assertEquals(0, self._error_count) 74 self.assertEquals(0, len(self._error_messages)) 75 76 def _call_error_handler(self, handle_error, confidence, line_number=100): 77 """Call the given error handler with a test error.""" 78 handle_error(line_number=line_number, 79 category=self._category, 80 confidence=confidence, 81 message="message") 82 83 def test_eq__true_return_value(self): 84 """Test the __eq__() method for the return value of True.""" 85 handler1 = self._error_handler(configuration=None) 86 handler2 = self._error_handler(configuration=None) 87 88 self.assertTrue(handler1.__eq__(handler2)) 89 90 def test_eq__false_return_value(self): 91 """Test the __eq__() method for the return value of False.""" 92 def make_handler(configuration=self._style_checker_configuration(), 93 file_path='foo.txt', increment_error_count=lambda: True, 94 line_numbers=[100]): 95 return DefaultStyleErrorHandler(configuration=configuration, 96 file_path=file_path, 97 increment_error_count=increment_error_count, 98 line_numbers=line_numbers) 99 100 handler = make_handler() 101 102 # Establish a baseline for our comparisons below. 103 self.assertTrue(handler.__eq__(make_handler())) 104 105 # Verify that a difference in any argument causes equality to fail. 106 self.assertFalse(handler.__eq__(make_handler(configuration=None))) 107 self.assertFalse(handler.__eq__(make_handler(file_path='bar.txt'))) 108 self.assertFalse(handler.__eq__(make_handler(increment_error_count=None))) 109 self.assertFalse(handler.__eq__(make_handler(line_numbers=[50]))) 110 111 def test_ne(self): 112 """Test the __ne__() method.""" 113 # By default, __ne__ always returns true on different objects. 114 # Thus, check just the distinguishing case to verify that the 115 # code defines __ne__. 116 handler1 = self._error_handler(configuration=None) 117 handler2 = self._error_handler(configuration=None) 118 119 self.assertFalse(handler1.__ne__(handler2)) 120 121 def test_non_reportable_error(self): 122 """Test __call__() with a non-reportable error.""" 123 self._check_initialized() 124 configuration = self._style_checker_configuration() 125 126 confidence = 1 127 # Confirm the error is not reportable. 128 self.assertFalse(configuration.is_reportable(self._category, 129 confidence, 130 self._file_path)) 131 error_handler = self._error_handler(configuration) 132 self._call_error_handler(error_handler, confidence) 133 134 self.assertEquals(0, self._error_count) 135 self.assertEquals([], self._error_messages) 136 137 # Also serves as a reportable error test. 138 def test_max_reports_per_category(self): 139 """Test error report suppression in __call__() method.""" 140 self._check_initialized() 141 configuration = self._style_checker_configuration() 142 error_handler = self._error_handler(configuration) 143 144 confidence = 5 145 146 # First call: usual reporting. 147 self._call_error_handler(error_handler, confidence) 148 self.assertEquals(1, self._error_count) 149 self.assertEquals(1, len(self._error_messages)) 150 self.assertEquals(self._error_messages, 151 ["foo.h(100): message [whitespace/tab] [5]\n"]) 152 153 # Second call: suppression message reported. 154 self._call_error_handler(error_handler, confidence) 155 # The "Suppressing further..." message counts as an additional 156 # message (but not as an addition to the error count). 157 self.assertEquals(2, self._error_count) 158 self.assertEquals(3, len(self._error_messages)) 159 self.assertEquals(self._error_messages[-2], 160 "foo.h(100): message [whitespace/tab] [5]\n") 161 self.assertEquals(self._error_messages[-1], 162 "Suppressing further [whitespace/tab] reports " 163 "for this file.\n") 164 165 # Third call: no report. 166 self._call_error_handler(error_handler, confidence) 167 self.assertEquals(3, self._error_count) 168 self.assertEquals(3, len(self._error_messages)) 169 170 def test_line_numbers(self): 171 """Test the line_numbers parameter.""" 172 self._check_initialized() 173 configuration = self._style_checker_configuration() 174 error_handler = self._error_handler(configuration, 175 line_numbers=[50]) 176 confidence = 5 177 178 # Error on non-modified line: no error. 179 self._call_error_handler(error_handler, confidence, line_number=60) 180 self.assertEquals(0, self._error_count) 181 self.assertEquals([], self._error_messages) 182 183 # Error on modified line: error. 184 self._call_error_handler(error_handler, confidence, line_number=50) 185 self.assertEquals(1, self._error_count) 186 self.assertEquals(self._error_messages, 187 ["foo.h(50): message [whitespace/tab] [5]\n"]) 188