| 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 |