diff -r 9dc5bdab157e Lib/unittest/case.py --- a/Lib/unittest/case.py Sun Sep 08 20:43:02 2013 +0300 +++ b/Lib/unittest/case.py Tue Sep 10 19:31:20 2013 +0300 @@ -11,7 +11,7 @@ from . import result from .util import (strclass, safe_repr, _count_diff_all_purpose, - _count_diff_hashable) + _count_diff_hashable, _common_shorten) __unittest = True @@ -673,7 +673,8 @@ def _baseAssertEqual(self, first, second, msg=None): """The default assertEqual implementation, not type specific.""" if not first == second: - standardMsg = '%s != %s' % (safe_repr(first), safe_repr(second)) + standardMsg = '%s != %s' % _common_shorten(safe_repr(first), + safe_repr(second)) msg = self._formatMessage(msg, standardMsg) raise self.failureException(msg) @@ -808,13 +809,8 @@ if seq1 == seq2: return - seq1_repr = safe_repr(seq1) - seq2_repr = safe_repr(seq2) - if len(seq1_repr) > 30: - seq1_repr = seq1_repr[:30] + '...' - if len(seq2_repr) > 30: - seq2_repr = seq2_repr[:30] + '...' - elements = (seq_type_name.capitalize(), seq1_repr, seq2_repr) + elements = (seq_type_name.capitalize(),) + _common_shorten( + safe_repr(seq1), safe_repr(seq2)) differing = '%ss differ: %s != %s\n' % elements for i in range(min(len1, len2)): @@ -973,7 +969,8 @@ self.assertIsInstance(d2, dict, 'Second argument is not a dictionary') if d1 != d2: - standardMsg = '%s != %s' % (safe_repr(d1, True), safe_repr(d2, True)) + standardMsg = '%s != %s' % _common_shorten(safe_repr(d1), + safe_repr(d2)) diff = ('\n' + '\n'.join(difflib.ndiff( pprint.pformat(d1).splitlines(), pprint.pformat(d2).splitlines()))) @@ -1057,8 +1054,8 @@ if len(firstlines) == 1 and first.strip('\r\n') == first: firstlines = [first + '\n'] secondlines = [second + '\n'] - standardMsg = '%s != %s' % (safe_repr(first, True), - safe_repr(second, True)) + standardMsg = '%s != %s' % _common_shorten(safe_repr(first), + safe_repr(second)) diff = '\n' + ''.join(difflib.ndiff(firstlines, secondlines)) standardMsg = self._truncateMessage(standardMsg, diff) self.fail(self._formatMessage(msg, standardMsg)) diff -r 9dc5bdab157e Lib/unittest/test/test_case.py --- a/Lib/unittest/test/test_case.py Sun Sep 08 20:43:02 2013 +0300 +++ b/Lib/unittest/test/test_case.py Tue Sep 10 19:31:20 2013 +0300 @@ -821,18 +821,18 @@ # set a lower threshold value and add a cleanup to restore it old_threshold = self._diffThreshold - self._diffThreshold = 2**8 + self._diffThreshold = 2**5 self.addCleanup(lambda: setattr(self, '_diffThreshold', old_threshold)) # under the threshold: diff marker (^) in error message - s = 'x' * (2**7) + s = 'x' * (2**4) with self.assertRaises(self.failureException) as cm: self.assertEqual(s + 'a', s + 'b') self.assertIn('^', str(cm.exception)) self.assertEqual(s + 'a', s + 'a') # over the threshold: diff not used and marker (^) not in error message - s = 'x' * (2**9) + s = 'x' * (2**6) # if the path that uses difflib is taken, _truncateMessage will be # called -- replace it with explodingTruncation to verify that this # doesn't happen @@ -849,6 +849,37 @@ self.assertEqual(str(cm.exception), '%r != %r' % (s1, s2)) self.assertEqual(s + 'a', s + 'a') + def testAssertEqual_shorten(self): + # set a lower threshold value and add a cleanup to restore it + old_threshold = self._diffThreshold + self._diffThreshold = 0 + self.addCleanup(lambda: setattr(self, '_diffThreshold', old_threshold)) + + s = 'x' * 100 + s1, s2 = s + 'a', s + 'b' + with self.assertRaises(self.failureException) as cm: + self.assertEqual(s1, s2) + c = 'xxxx[35 chars]' + 'x' * 61 + self.assertEqual(str(cm.exception), "'%sa' != '%sb'" % (c, c)) + self.assertEqual(s + 'a', s + 'a') + + p = 'y' * 50 + s1, s2 = s + 'a' + p, s + 'b' + p + with self.assertRaises(self.failureException) as cm: + self.assertEqual(s1, s2) + c = 'xxxx[85 chars]xxxxxxxxxxx' + #print() + #print(str(cm.exception)) + self.assertEqual(str(cm.exception), "'%sa%s' != '%sb%s'" % (c, p, c, p)) + + p = 'y' * 100 + s1, s2 = s + 'a' + p, s + 'b' + p + with self.assertRaises(self.failureException) as cm: + self.assertEqual(s1, s2) + c = 'xxxx[91 chars]xxxxx' + d = 'y' * 40 + '[56 chars]yyyy' + self.assertEqual(str(cm.exception), "'%sa%s' != '%sb%s'" % (c, d, c, d)) + def testAssertCountEqual(self): a = object() self.assertCountEqual([1, 2, 3], [3, 2, 1]) diff -r 9dc5bdab157e Lib/unittest/util.py --- a/Lib/unittest/util.py Sun Sep 08 20:43:02 2013 +0300 +++ b/Lib/unittest/util.py Tue Sep 10 19:31:20 2013 +0300 @@ -1,10 +1,46 @@ """Various utility functions.""" from collections import namedtuple, OrderedDict +from os.path import commonprefix __unittest = True _MAX_LENGTH = 80 +_PLACEHOLDER_LEN = 12 +_MIN_BEGIN_LEN = 5 +_MIN_END_LEN = 5 +_MIN_COMMON_LEN = 5 +_MIN_DIFF_LEN = _MAX_LENGTH - \ + (_MIN_BEGIN_LEN + _PLACEHOLDER_LEN + _MIN_COMMON_LEN + + _PLACEHOLDER_LEN + _MIN_END_LEN) +assert _MIN_DIFF_LEN >= 0 + +def _shorten(s, prefixlen, suffixlen): + skip = len(s) - prefixlen - suffixlen + if skip > _PLACEHOLDER_LEN: + s = '%s[%d chars]%s' % (s[:prefixlen], skip, s[len(s) - suffixlen:]) + return s + +def _common_shorten(*args): + maxlen = max(map(len, args)) + if maxlen <= _MAX_LENGTH: + return args + + prefix = commonprefix(args) + prefixlen = len(prefix) + + common_len = _MAX_LENGTH - \ + (maxlen - prefixlen + _MIN_BEGIN_LEN + _PLACEHOLDER_LEN) + if common_len > _MIN_COMMON_LEN: + assert _MIN_BEGIN_LEN + _PLACEHOLDER_LEN + _MIN_COMMON_LEN + \ + (maxlen - prefixlen) < _MAX_LENGTH + prefix = _shorten(prefix, _MIN_BEGIN_LEN, common_len) + return tuple(prefix + s[prefixlen:] for s in args) + + prefix = _shorten(prefix, _MIN_BEGIN_LEN, _MIN_COMMON_LEN) + return tuple(prefix + _shorten(s[prefixlen:], _MIN_DIFF_LEN, _MIN_END_LEN) + for s in args) + def safe_repr(obj, short=False): try: result = repr(obj)