OLD | NEW |
1 # -*- coding: utf-8; -*- | 1 # -*- coding: utf-8; -*- |
2 # | 2 # |
3 # Copyright (C) 2011 Google Inc. All rights reserved. | 3 # Copyright (C) 2011 Google Inc. All rights reserved. |
4 # Copyright (C) 2009 Torch Mobile Inc. | 4 # Copyright (C) 2009 Torch Mobile Inc. |
5 # Copyright (C) 2009 Apple Inc. All rights reserved. | 5 # Copyright (C) 2009 Apple Inc. All rights reserved. |
6 # Copyright (C) 2010 Chris Jerdonek (cjerdonek@webkit.org) | 6 # Copyright (C) 2010 Chris Jerdonek (cjerdonek@webkit.org) |
7 # | 7 # |
8 # Redistribution and use in source and binary forms, with or without | 8 # Redistribution and use in source and binary forms, with or without |
9 # modification, are permitted provided that the following conditions are | 9 # modification, are permitted provided that the following conditions are |
10 # met: | 10 # met: |
(...skipping 17 matching lines...) Expand all Loading... |
28 # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | 28 # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
29 # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | 29 # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
30 # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | 30 # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
31 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | 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. | 32 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
33 | 33 |
34 """Unit test for cpp_style.py.""" | 34 """Unit test for cpp_style.py.""" |
35 | 35 |
36 # FIXME: Add a good test that tests UpdateIncludeState. | 36 # FIXME: Add a good test that tests UpdateIncludeState. |
37 | 37 |
38 import codecs | |
39 import os | 38 import os |
40 import random | 39 import random |
41 import re | 40 import re |
42 import webkitpy.thirdparty.unittest2 as unittest | 41 import webkitpy.thirdparty.unittest2 as unittest |
43 import cpp as cpp_style | 42 import cpp as cpp_style |
44 from cpp import CppChecker | 43 from cpp import CppChecker |
45 from ..filter import FilterConfiguration | 44 from ..filter import FilterConfiguration |
| 45 from webkitpy.common.system.filesystem import FileSystem |
46 | 46 |
47 # This class works as an error collector and replaces cpp_style.Error | 47 # This class works as an error collector and replaces cpp_style.Error |
48 # function for the unit tests. We also verify each category we see | 48 # function for the unit tests. We also verify each category we see |
49 # is in STYLE_CATEGORIES, to help keep that list up to date. | 49 # is in STYLE_CATEGORIES, to help keep that list up to date. |
50 class ErrorCollector: | 50 class ErrorCollector: |
51 _all_style_categories = CppChecker.categories | 51 _all_style_categories = CppChecker.categories |
52 # This is a list including all categories seen in any unit test. | 52 # This is a list including all categories seen in any unit test. |
53 _seen_style_categories = {} | 53 _seen_style_categories = {} |
54 | 54 |
55 def __init__(self, assert_fn, filter=None, lines_to_check=None): | 55 def __init__(self, assert_fn, filter=None, lines_to_check=None): |
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
92 this isn't called from within the normal unittest framework, we | 92 this isn't called from within the normal unittest framework, we |
93 can't use the normal unittest assert macros. Instead we just exit | 93 can't use the normal unittest assert macros. Instead we just exit |
94 when we see an error. Good thing this test is always run last! | 94 when we see an error. Good thing this test is always run last! |
95 """ | 95 """ |
96 for category in self._all_style_categories: | 96 for category in self._all_style_categories: |
97 if category not in self._seen_style_categories: | 97 if category not in self._seen_style_categories: |
98 import sys | 98 import sys |
99 sys.exit('FATAL ERROR: There are no tests for category "%s"' % c
ategory) | 99 sys.exit('FATAL ERROR: There are no tests for category "%s"' % c
ategory) |
100 | 100 |
101 | 101 |
102 # This class is a lame mock of codecs. We do not verify filename, mode, or | |
103 # encoding, but for the current use case it is not needed. | |
104 class MockIo: | |
105 def __init__(self, mock_file): | |
106 self.mock_file = mock_file | |
107 | |
108 def open(self, unused_filename, unused_mode, unused_encoding, _): # NOLINT | |
109 # (lint doesn't like open as a method name) | |
110 return self.mock_file | |
111 | |
112 | |
113 class CppFunctionsTest(unittest.TestCase): | 102 class CppFunctionsTest(unittest.TestCase): |
114 | 103 |
115 """Supports testing functions that do not need CppStyleTestBase.""" | 104 """Supports testing functions that do not need CppStyleTestBase.""" |
116 | 105 |
117 def test_convert_to_lower_with_underscores(self): | 106 def test_convert_to_lower_with_underscores(self): |
118 self.assertEqual(cpp_style._convert_to_lower_with_underscores('ABC'), 'a
bc') | 107 self.assertEqual(cpp_style._convert_to_lower_with_underscores('ABC'), 'a
bc') |
119 self.assertEqual(cpp_style._convert_to_lower_with_underscores('aB'), 'a_
b') | 108 self.assertEqual(cpp_style._convert_to_lower_with_underscores('aB'), 'a_
b') |
120 self.assertEqual(cpp_style._convert_to_lower_with_underscores('isAName')
, 'is_a_name') | 109 self.assertEqual(cpp_style._convert_to_lower_with_underscores('isAName')
, 'is_a_name') |
121 self.assertEqual(cpp_style._convert_to_lower_with_underscores('AnotherTe
st'), 'another_test') | 110 self.assertEqual(cpp_style._convert_to_lower_with_underscores('AnotherTe
st'), 'another_test') |
122 self.assertEqual(cpp_style._convert_to_lower_with_underscores('PassRefPt
r<MyClass>'), 'pass_ref_ptr<my_class>') | 111 self.assertEqual(cpp_style._convert_to_lower_with_underscores('PassRefPt
r<MyClass>'), 'pass_ref_ptr<my_class>') |
(...skipping 116 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
239 level for the tests. | 228 level for the tests. |
240 | 229 |
241 """ | 230 """ |
242 | 231 |
243 # FIXME: Refactor the unit tests so the confidence level is passed | 232 # FIXME: Refactor the unit tests so the confidence level is passed |
244 # explicitly, just like it is in the real code. | 233 # explicitly, just like it is in the real code. |
245 min_confidence = 1; | 234 min_confidence = 1; |
246 | 235 |
247 # Helper function to avoid needing to explicitly pass confidence | 236 # Helper function to avoid needing to explicitly pass confidence |
248 # in all the unit test calls to cpp_style.process_file_data(). | 237 # in all the unit test calls to cpp_style.process_file_data(). |
249 def process_file_data(self, filename, file_extension, lines, error, unit_tes
t_config={}): | 238 def process_file_data(self, filename, file_extension, lines, error, fs=None)
: |
250 """Call cpp_style.process_file_data() with the min_confidence.""" | 239 """Call cpp_style.process_file_data() with the min_confidence.""" |
251 return cpp_style.process_file_data(filename, file_extension, lines, | 240 return cpp_style.process_file_data(filename, file_extension, lines, |
252 error, self.min_confidence, unit_test
_config) | 241 error, self.min_confidence, fs) |
253 | 242 |
254 def perform_lint(self, code, filename, basic_error_rules, unit_test_config={
}, lines_to_check=None): | 243 def perform_lint(self, code, filename, basic_error_rules, fs=None, lines_to_
check=None): |
255 error_collector = ErrorCollector(self.assertTrue, FilterConfiguration(ba
sic_error_rules), lines_to_check) | 244 error_collector = ErrorCollector(self.assertTrue, FilterConfiguration(ba
sic_error_rules), lines_to_check) |
256 lines = code.split('\n') | 245 lines = code.split('\n') |
257 extension = filename.split('.')[1] | 246 extension = filename.split('.')[1] |
258 self.process_file_data(filename, extension, lines, error_collector, unit
_test_config) | 247 self.process_file_data(filename, extension, lines, error_collector, fs) |
259 return error_collector.results() | 248 return error_collector.results() |
260 | 249 |
261 # Perform lint on single line of input and return the error message. | 250 # Perform lint on single line of input and return the error message. |
262 def perform_single_line_lint(self, code, filename): | 251 def perform_single_line_lint(self, code, filename): |
263 basic_error_rules = ('-build/header_guard', | 252 basic_error_rules = ('-build/header_guard', |
264 '-legal/copyright', | 253 '-legal/copyright', |
265 '-readability/fn_size', | 254 '-readability/fn_size', |
266 '-readability/parameter_name', | 255 '-readability/parameter_name', |
267 '-readability/pass_ptr', | 256 '-readability/pass_ptr', |
268 '-whitespace/ending_newline') | 257 '-whitespace/ending_newline') |
(...skipping 28 matching lines...) Expand all Loading... |
297 '+readability/pass_ptr') | 286 '+readability/pass_ptr') |
298 return self.perform_lint(code, 'test.cpp', basic_error_rules) | 287 return self.perform_lint(code, 'test.cpp', basic_error_rules) |
299 | 288 |
300 # Only keep leaky pattern errors. | 289 # Only keep leaky pattern errors. |
301 def perform_leaky_pattern_check(self, code): | 290 def perform_leaky_pattern_check(self, code): |
302 basic_error_rules = ('-', | 291 basic_error_rules = ('-', |
303 '+runtime/leaky_pattern') | 292 '+runtime/leaky_pattern') |
304 return self.perform_lint(code, 'test.cpp', basic_error_rules) | 293 return self.perform_lint(code, 'test.cpp', basic_error_rules) |
305 | 294 |
306 # Only include what you use errors. | 295 # Only include what you use errors. |
307 def perform_include_what_you_use(self, code, filename='foo.h', io=codecs): | 296 def perform_include_what_you_use(self, code, filename='foo.h', fs=None): |
308 basic_error_rules = ('-', | 297 basic_error_rules = ('-', |
309 '+build/include_what_you_use') | 298 '+build/include_what_you_use') |
310 unit_test_config = {cpp_style.INCLUDE_IO_INJECTION_KEY: io} | 299 return self.perform_lint(code, filename, basic_error_rules, fs) |
311 return self.perform_lint(code, filename, basic_error_rules, unit_test_co
nfig) | |
312 | 300 |
313 def perform_avoid_static_cast_of_objects(self, code, filename='foo.cpp', io=
codecs): | 301 def perform_avoid_static_cast_of_objects(self, code, filename='foo.cpp', fs=
None): |
314 basic_error_rules = ('-', | 302 basic_error_rules = ('-', |
315 '+runtime/casting') | 303 '+runtime/casting') |
316 unit_test_config = {cpp_style.INCLUDE_IO_INJECTION_KEY: io} | 304 return self.perform_lint(code, filename, basic_error_rules, fs) |
317 return self.perform_lint(code, filename, basic_error_rules, unit_test_co
nfig) | |
318 | 305 |
319 # Perform lint and compare the error message with "expected_message". | 306 # Perform lint and compare the error message with "expected_message". |
320 def assert_lint(self, code, expected_message, file_name='foo.cpp'): | 307 def assert_lint(self, code, expected_message, file_name='foo.cpp'): |
321 self.assertEqual(expected_message, self.perform_single_line_lint(code, f
ile_name)) | 308 self.assertEqual(expected_message, self.perform_single_line_lint(code, f
ile_name)) |
322 | 309 |
323 def assert_lint_one_of_many_errors_re(self, code, expected_message_re, file_
name='foo.cpp'): | 310 def assert_lint_one_of_many_errors_re(self, code, expected_message_re, file_
name='foo.cpp'): |
324 messages = self.perform_single_line_lint(code, file_name) | 311 messages = self.perform_single_line_lint(code, file_name) |
325 for message in messages: | 312 for message in messages: |
326 if re.search(expected_message_re, message): | 313 if re.search(expected_message_re, message): |
327 return | 314 return |
(...skipping 438 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
766 'Do not use dynamic_cast<>. If you need to cast within a class ' | 753 'Do not use dynamic_cast<>. If you need to cast within a class ' |
767 'hierarchy, use static_cast<> to upcast. Google doesn\'t support ' | 754 'hierarchy, use static_cast<> to upcast. Google doesn\'t support ' |
768 'RTTI. [runtime/rtti] [5]') | 755 'RTTI. [runtime/rtti] [5]') |
769 # dynamic_cast is disallowed in most files. | 756 # dynamic_cast is disallowed in most files. |
770 self.assert_language_rules_check('foo.cpp', statement, error_message) | 757 self.assert_language_rules_check('foo.cpp', statement, error_message) |
771 self.assert_language_rules_check('foo.h', statement, error_message) | 758 self.assert_language_rules_check('foo.h', statement, error_message) |
772 | 759 |
773 # Tests for static_cast readability. | 760 # Tests for static_cast readability. |
774 def test_static_cast_on_objects_with_toFoo(self): | 761 def test_static_cast_on_objects_with_toFoo(self): |
775 mock_header_contents = ['inline Foo* toFoo(Bar* bar)'] | 762 mock_header_contents = ['inline Foo* toFoo(Bar* bar)'] |
776 message = self.perform_avoid_static_cast_of_objects( | 763 fs = FileSystem() |
777 'Foo* x = static_cast<Foo*>(bar);', | 764 orig_read_text_file_fn = fs.read_text_file |
778 filename='casting.cpp', | 765 |
779 io=MockIo(mock_header_contents)) | 766 def mock_read_text_file_fn(path): |
780 self.assertEqual(message, 'static_cast of class objects is not allowed.
Use toFoo defined in Foo.h.' | 767 return mock_header_contents |
781 ' [runtime/casting] [4]') | 768 |
| 769 try: |
| 770 fs.read_text_file = mock_read_text_file_fn |
| 771 message = self.perform_avoid_static_cast_of_objects( |
| 772 'Foo* x = static_cast<Foo*>(bar);', |
| 773 filename='casting.cpp', |
| 774 fs=fs) |
| 775 self.assertEqual(message, 'static_cast of class objects is not allow
ed. Use toFoo defined in Foo.h.' |
| 776 ' [runtime/casting] [4]') |
| 777 finally: |
| 778 fs.read_text_file = orig_read_text_file_fn |
782 | 779 |
783 def test_static_cast_on_objects_without_toFoo(self): | 780 def test_static_cast_on_objects_without_toFoo(self): |
784 mock_header_contents = ['inline FooBar* toFooBar(Bar* bar)'] | 781 mock_header_contents = ['inline FooBar* toFooBar(Bar* bar)'] |
785 message = self.perform_avoid_static_cast_of_objects( | 782 fs = FileSystem() |
786 'Foo* x = static_cast<Foo*>(bar);', | 783 orig_read_text_file_fn = fs.read_text_file |
787 filename='casting.cpp', | 784 |
788 io=MockIo(mock_header_contents)) | 785 def mock_read_text_file_fn(path): |
789 self.assertEqual(message, 'static_cast of class objects is not allowed.
Add toFoo in Foo.h and use it instead.' | 786 return mock_header_contents |
790 ' [runtime/casting] [4]') | 787 |
| 788 try: |
| 789 fs.read_text_file = mock_read_text_file_fn |
| 790 message = self.perform_avoid_static_cast_of_objects( |
| 791 'Foo* x = static_cast<Foo*>(bar);', |
| 792 filename='casting.cpp', |
| 793 fs=fs) |
| 794 self.assertEqual(message, 'static_cast of class objects is not allow
ed. Add toFoo in Foo.h and use it instead.' |
| 795 ' [runtime/casting] [4]') |
| 796 finally: |
| 797 fs.read_text_file = orig_read_text_file_fn |
791 | 798 |
792 # We cannot test this functionality because of difference of | 799 # We cannot test this functionality because of difference of |
793 # function definitions. Anyway, we may never enable this. | 800 # function definitions. Anyway, we may never enable this. |
794 # | 801 # |
795 # # Test for unnamed arguments in a method. | 802 # # Test for unnamed arguments in a method. |
796 # def test_check_for_unnamed_params(self): | 803 # def test_check_for_unnamed_params(self): |
797 # message = ('All parameters should be named in a function' | 804 # message = ('All parameters should be named in a function' |
798 # ' [readability/function] [3]') | 805 # ' [readability/function] [3]') |
799 # self.assert_lint('virtual void A(int*) const;', message) | 806 # self.assert_lint('virtual void A(int*) const;', message) |
800 # self.assert_lint('virtual void B(void (*fn)(int*));', message) | 807 # self.assert_lint('virtual void B(void (*fn)(int*));', message) |
(...skipping 206 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1007 'Add #include <limits> for numeric_limits<>' | 1014 'Add #include <limits> for numeric_limits<>' |
1008 ' [build/include_what_you_use] [4]') | 1015 ' [build/include_what_you_use] [4]') |
1009 self.assert_include_what_you_use( | 1016 self.assert_include_what_you_use( |
1010 '''#include <limits> | 1017 '''#include <limits> |
1011 int i = numeric_limits<int>::max() | 1018 int i = numeric_limits<int>::max() |
1012 ''', | 1019 ''', |
1013 '') | 1020 '') |
1014 | 1021 |
1015 # Test the UpdateIncludeState code path. | 1022 # Test the UpdateIncludeState code path. |
1016 mock_header_contents = ['#include "blah/foo.h"', '#include "blah/bar.h"'
] | 1023 mock_header_contents = ['#include "blah/foo.h"', '#include "blah/bar.h"'
] |
1017 message = self.perform_include_what_you_use( | 1024 fs = FileSystem() |
1018 '#include "config.h"\n' | 1025 orig_read_text_file_fn = fs.read_text_file |
1019 '#include "blah/a.h"\n', | |
1020 filename='blah/a.cpp', | |
1021 io=MockIo(mock_header_contents)) | |
1022 self.assertEqual(message, '') | |
1023 | 1026 |
1024 mock_header_contents = ['#include <set>'] | 1027 def mock_read_text_file_fn(path): |
1025 message = self.perform_include_what_you_use( | 1028 return mock_header_contents |
1026 '''#include "config.h" | |
1027 #include "blah/a.h" | |
1028 | 1029 |
1029 std::set<int> foo;''', | 1030 try: |
1030 filename='blah/a.cpp', | 1031 fs.read_text_file = mock_read_text_file_fn |
1031 io=MockIo(mock_header_contents)) | 1032 message = self.perform_include_what_you_use( |
1032 self.assertEqual(message, '') | 1033 '#include "config.h"\n' |
| 1034 '#include "blah/a.h"\n', |
| 1035 filename='blah/a.cpp', |
| 1036 fs=fs) |
| 1037 self.assertEqual(message, '') |
1033 | 1038 |
1034 # If there's just a .cpp and the header can't be found then it's ok. | 1039 mock_header_contents = ['#include <set>'] |
1035 message = self.perform_include_what_you_use( | 1040 message = self.perform_include_what_you_use( |
1036 '''#include "config.h" | 1041 '''#include "config.h" |
1037 #include "blah/a.h" | 1042 #include "blah/a.h" |
1038 | 1043 |
1039 std::set<int> foo;''', | 1044 std::set<int> foo;''', |
1040 filename='blah/a.cpp') | 1045 filename='blah/a.cpp', |
1041 self.assertEqual(message, '') | 1046 fs=fs) |
| 1047 self.assertEqual(message, '') |
1042 | 1048 |
1043 # Make sure we find the headers with relative paths. | 1049 # If there's just a .cpp and the header can't be found then it's ok. |
1044 mock_header_contents = [''] | 1050 message = self.perform_include_what_you_use( |
1045 message = self.perform_include_what_you_use( | 1051 '''#include "config.h" |
1046 '''#include "config.h" | 1052 #include "blah/a.h" |
1047 #include "%s%sa.h" | |
1048 | 1053 |
1049 std::set<int> foo;''' % (os.path.basename(os.getcwd()), os.path.s
ep), | 1054 std::set<int> foo;''', |
1050 filename='a.cpp', | 1055 filename='blah/a.cpp') |
1051 io=MockIo(mock_header_contents)) | 1056 self.assertEqual(message, '') |
1052 self.assertEqual(message, 'Add #include <set> for set<> ' | 1057 |
1053 '[build/include_what_you_use] [4]') | 1058 # Make sure we find the headers with relative paths. |
| 1059 mock_header_contents = [''] |
| 1060 message = self.perform_include_what_you_use( |
| 1061 '''#include "config.h" |
| 1062 #include "%s%sa.h" |
| 1063 |
| 1064 std::set<int> foo;''' % (os.path.basename(os.getcwd()), os.pa
th.sep), |
| 1065 filename='a.cpp', |
| 1066 fs=fs) |
| 1067 self.assertEqual(message, 'Add #include <set> for set<> ' |
| 1068 '[build/include_what_you_use] [4]') |
| 1069 finally: |
| 1070 fs.read_text_file = orig_read_text_file_fn |
1054 | 1071 |
1055 def test_files_belong_to_same_module(self): | 1072 def test_files_belong_to_same_module(self): |
1056 f = cpp_style.files_belong_to_same_module | 1073 f = cpp_style.files_belong_to_same_module |
1057 self.assertEqual((True, ''), f('a.cpp', 'a.h')) | 1074 self.assertEqual((True, ''), f('a.cpp', 'a.h')) |
1058 self.assertEqual((True, ''), f('base/google.cpp', 'base/google.h')) | 1075 self.assertEqual((True, ''), f('base/google.cpp', 'base/google.h')) |
1059 self.assertEqual((True, ''), f('base/google_test.cpp', 'base/google.h')) | 1076 self.assertEqual((True, ''), f('base/google_test.cpp', 'base/google.h')) |
1060 self.assertEqual((True, ''), | 1077 self.assertEqual((True, ''), |
1061 f('base/google_unittest.cpp', 'base/google.h')) | 1078 f('base/google_unittest.cpp', 'base/google.h')) |
1062 self.assertEqual((True, ''), | 1079 self.assertEqual((True, ''), |
1063 f('base/internal/google_unittest.cpp', | 1080 f('base/internal/google_unittest.cpp', |
(...skipping 4104 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5168 def test_ne(self): | 5185 def test_ne(self): |
5169 """Test __ne__ inequality function.""" | 5186 """Test __ne__ inequality function.""" |
5170 checker1 = self._checker() | 5187 checker1 = self._checker() |
5171 checker2 = self._checker() | 5188 checker2 = self._checker() |
5172 | 5189 |
5173 # != calls __ne__. | 5190 # != calls __ne__. |
5174 # By default, __ne__ always returns true on different objects. | 5191 # By default, __ne__ always returns true on different objects. |
5175 # Thus, just check the distinguishing case to verify that the | 5192 # Thus, just check the distinguishing case to verify that the |
5176 # code defines __ne__. | 5193 # code defines __ne__. |
5177 self.assertFalse(checker1 != checker2) | 5194 self.assertFalse(checker1 != checker2) |
OLD | NEW |