Skip to content

Commit 42efe70

Browse files
committed
Correcting message display issue causing output of assertMultiLineEqual to be garbled.
1 parent dc3f975 commit 42efe70

File tree

3 files changed

+90
-12
lines changed

3 files changed

+90
-12
lines changed

Lib/test/test_unittest/test_assertions.py

+3-3
Original file line numberDiff line numberDiff line change
@@ -273,9 +273,9 @@ def testAssertDictEqual(self):
273273

274274
def testAssertMultiLineEqual(self):
275275
self.assertMessages('assertMultiLineEqual', ("", "foo"),
276-
[r"\+ foo$", "^oops$",
277-
r"\+ foo$",
278-
r"\+ foo : oops$"])
276+
[r"\+ foo\n$", "^oops$",
277+
r"\+ foo\n$",
278+
r"\+ foo\n : oops$"])
279279

280280
def testAssertLess(self):
281281
self.assertMessages('assertLess', (2, 1),

Lib/test/test_unittest/test_case.py

+60
Original file line numberDiff line numberDiff line change
@@ -1149,6 +1149,66 @@ def testAssertEqualSingleLine(self):
11491149
error = str(e).split('\n', 1)[1]
11501150
self.assertEqual(sample_text_error, error)
11511151

1152+
def testAssertEqualwithEmptyString(self):
1153+
'''Verify when there is an empty string involved, the diff output
1154+
does not treat the empty string as a single empty line. It should
1155+
instead be handled as a non-line.
1156+
'''
1157+
sample_text = ''
1158+
revised_sample_text = 'unladen swallows fly quickly'
1159+
sample_text_error = '''\
1160+
+ unladen swallows fly quickly
1161+
'''
1162+
try:
1163+
self.assertEqual(sample_text, revised_sample_text)
1164+
except self.failureException as e:
1165+
# need to remove the first line of the error message
1166+
error = str(e).split('\n', 1)[1]
1167+
self.assertEqual(sample_text_error, error)
1168+
1169+
def testAssertEqualMultipleLinesMissingNewlineTerminator(self):
1170+
'''Verifying format of diff output from assertEqual involving strings
1171+
with multiple lines, but missing the terminating newline on both.
1172+
'''
1173+
sample_text = 'laden swallows\nfly sloely'
1174+
revised_sample_text = 'laden swallows\nfly slowly'
1175+
sample_text_error = '''\
1176+
laden swallows
1177+
- fly sloely
1178+
? ^
1179+
+ fly slowly
1180+
? ^
1181+
'''
1182+
try:
1183+
self.assertEqual(sample_text, revised_sample_text)
1184+
except self.failureException as e:
1185+
# need to remove the first line of the error message
1186+
error = str(e).split('\n', 1)[1]
1187+
self.assertEqual(sample_text_error, error)
1188+
1189+
def testAssertEqualMultipleLinesMismatchedNewlinesTerminators(self):
1190+
'''Verifying format of diff output from assertEqual involving strings
1191+
with multiple lines and mismatched newlines. The output should
1192+
include a - on it's own line to indicate the newline difference
1193+
between the two strings
1194+
'''
1195+
sample_text = 'laden swallows\nfly sloely\n'
1196+
revised_sample_text = 'laden swallows\nfly slowly'
1197+
sample_text_error = '''\
1198+
laden swallows
1199+
- fly sloely
1200+
? ^
1201+
+ fly slowly
1202+
? ^
1203+
-\x20
1204+
'''
1205+
try:
1206+
self.assertEqual(sample_text, revised_sample_text)
1207+
except self.failureException as e:
1208+
# need to remove the first line of the error message
1209+
error = str(e).split('\n', 1)[1]
1210+
self.assertEqual(sample_text_error, error)
1211+
11521212
def testEqualityBytesWarning(self):
11531213
if sys.flags.bytes_warning:
11541214
def bytes_warning():

Lib/unittest/case.py

+27-9
Original file line numberDiff line numberDiff line change
@@ -1216,20 +1216,38 @@ def assertCountEqual(self, first, second, msg=None):
12161216
self.fail(msg)
12171217

12181218
def assertMultiLineEqual(self, first, second, msg=None):
1219-
"""Assert that two multi-line strings are equal."""
1220-
self.assertIsInstance(first, str, 'First argument is not a string')
1221-
self.assertIsInstance(second, str, 'Second argument is not a string')
1219+
"""Assert that two multi-line strings are equal.
1220+
If the assertion fails, then provide an error message with a detailed
1221+
diff output
1222+
"""
1223+
self.assertIsInstance(first, str, "First argument is not a string")
1224+
self.assertIsInstance(second, str, "Second argument is not a string")
12221225

12231226
if first != second:
1224-
# don't use difflib if the strings are too long
1227+
# Don't use difflib if the strings are too long
12251228
if (len(first) > self._diffThreshold or
12261229
len(second) > self._diffThreshold):
12271230
self._baseAssertEqual(first, second, msg)
1228-
firstlines = first.splitlines(keepends=True)
1229-
secondlines = second.splitlines(keepends=True)
1230-
if len(firstlines) == 1 and first.strip('\r\n') == first:
1231-
firstlines = [first + '\n']
1232-
secondlines = [second + '\n']
1231+
1232+
# Append \n to both strings if either is missing the \n.
1233+
# This allows the final ndiff to show the \n difference. The
1234+
# exception here is if the string is empty, in which case no
1235+
# \n should be added
1236+
first_presplit = first
1237+
second_presplit = second
1238+
if first != '' and second != '':
1239+
if first[-1] != '\n' or second[-1] != '\n':
1240+
first_presplit += '\n'
1241+
second_presplit += '\n'
1242+
elif first == '' and second != '' and second[-1] != '\n':
1243+
second_presplit += '\n'
1244+
elif second == '' and first != '' and first[-1] != '\n':
1245+
first_presplit += '\n'
1246+
1247+
firstlines = first_presplit.splitlines(keepends=True)
1248+
secondlines = second_presplit.splitlines(keepends=True)
1249+
1250+
# Generate the message and diff, then raise the exception
12331251
standardMsg = '%s != %s' % _common_shorten_repr(first, second)
12341252
diff = '\n' + ''.join(difflib.ndiff(firstlines, secondlines))
12351253
standardMsg = self._truncateMessage(standardMsg, diff)

0 commit comments

Comments
 (0)