summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMichael Blahay <mblahay@users.noreply.github.com>2023-05-04 22:37:17 (GMT)
committerGitHub <noreply@github.com>2023-05-04 22:37:17 (GMT)
commit46361bb84332800bc3632688e6ef3b4dd4a48723 (patch)
tree040035775dd304158eb242d04b38bd9324628afe
parent7d35c3121ade679dd6e8b4a0bac7b3702aee6921 (diff)
downloadcpython-46361bb84332800bc3632688e6ef3b4dd4a48723.zip
cpython-46361bb84332800bc3632688e6ef3b4dd4a48723.tar.gz
cpython-46361bb84332800bc3632688e6ef3b4dd4a48723.tar.bz2
gh-68968: Correcting message display issue with assertEqual (#103937)
-rw-r--r--Lib/test/test_unittest/test_assertions.py6
-rw-r--r--Lib/test/test_unittest/test_case.py60
-rw-r--r--Lib/unittest/case.py31
-rw-r--r--Misc/NEWS.d/next/Library/2023-04-27-18-46-31.gh-issue-68968.E3tnhy.rst1
4 files changed, 87 insertions, 11 deletions
diff --git a/Lib/test/test_unittest/test_assertions.py b/Lib/test/test_unittest/test_assertions.py
index 6557104..5c1a28e 100644
--- a/Lib/test/test_unittest/test_assertions.py
+++ b/Lib/test/test_unittest/test_assertions.py
@@ -273,9 +273,9 @@ class TestLongMessage(unittest.TestCase):
def testAssertMultiLineEqual(self):
self.assertMessages('assertMultiLineEqual', ("", "foo"),
- [r"\+ foo$", "^oops$",
- r"\+ foo$",
- r"\+ foo : oops$"])
+ [r"\+ foo\n$", "^oops$",
+ r"\+ foo\n$",
+ r"\+ foo\n : oops$"])
def testAssertLess(self):
self.assertMessages('assertLess', (2, 1),
diff --git a/Lib/test/test_unittest/test_case.py b/Lib/test/test_unittest/test_case.py
index dd5ff6d..ed5eb56 100644
--- a/Lib/test/test_unittest/test_case.py
+++ b/Lib/test/test_unittest/test_case.py
@@ -1149,6 +1149,66 @@ test case
error = str(e).split('\n', 1)[1]
self.assertEqual(sample_text_error, error)
+ def testAssertEqualwithEmptyString(self):
+ '''Verify when there is an empty string involved, the diff output
+ does not treat the empty string as a single empty line. It should
+ instead be handled as a non-line.
+ '''
+ sample_text = ''
+ revised_sample_text = 'unladen swallows fly quickly'
+ sample_text_error = '''\
++ unladen swallows fly quickly
+'''
+ try:
+ self.assertEqual(sample_text, revised_sample_text)
+ except self.failureException as e:
+ # need to remove the first line of the error message
+ error = str(e).split('\n', 1)[1]
+ self.assertEqual(sample_text_error, error)
+
+ def testAssertEqualMultipleLinesMissingNewlineTerminator(self):
+ '''Verifying format of diff output from assertEqual involving strings
+ with multiple lines, but missing the terminating newline on both.
+ '''
+ sample_text = 'laden swallows\nfly sloely'
+ revised_sample_text = 'laden swallows\nfly slowly'
+ sample_text_error = '''\
+ laden swallows
+- fly sloely
+? ^
++ fly slowly
+? ^
+'''
+ try:
+ self.assertEqual(sample_text, revised_sample_text)
+ except self.failureException as e:
+ # need to remove the first line of the error message
+ error = str(e).split('\n', 1)[1]
+ self.assertEqual(sample_text_error, error)
+
+ def testAssertEqualMultipleLinesMismatchedNewlinesTerminators(self):
+ '''Verifying format of diff output from assertEqual involving strings
+ with multiple lines and mismatched newlines. The output should
+ include a - on it's own line to indicate the newline difference
+ between the two strings
+ '''
+ sample_text = 'laden swallows\nfly sloely\n'
+ revised_sample_text = 'laden swallows\nfly slowly'
+ sample_text_error = '''\
+ laden swallows
+- fly sloely
+? ^
++ fly slowly
+? ^
+-\x20
+'''
+ try:
+ self.assertEqual(sample_text, revised_sample_text)
+ except self.failureException as e:
+ # need to remove the first line of the error message
+ error = str(e).split('\n', 1)[1]
+ self.assertEqual(sample_text_error, error)
+
def testEqualityBytesWarning(self):
if sys.flags.bytes_warning:
def bytes_warning():
diff --git a/Lib/unittest/case.py b/Lib/unittest/case.py
index 018f22e..001b640 100644
--- a/Lib/unittest/case.py
+++ b/Lib/unittest/case.py
@@ -1217,19 +1217,34 @@ class TestCase(object):
def assertMultiLineEqual(self, first, second, msg=None):
"""Assert that two multi-line strings are equal."""
- self.assertIsInstance(first, str, 'First argument is not a string')
- self.assertIsInstance(second, str, 'Second argument is not a string')
+ self.assertIsInstance(first, str, "First argument is not a string")
+ self.assertIsInstance(second, str, "Second argument is not a string")
if first != second:
- # don't use difflib if the strings are too long
+ # Don't use difflib if the strings are too long
if (len(first) > self._diffThreshold or
len(second) > self._diffThreshold):
self._baseAssertEqual(first, second, msg)
- firstlines = first.splitlines(keepends=True)
- secondlines = second.splitlines(keepends=True)
- if len(firstlines) == 1 and first.strip('\r\n') == first:
- firstlines = [first + '\n']
- secondlines = [second + '\n']
+
+ # Append \n to both strings if either is missing the \n.
+ # This allows the final ndiff to show the \n difference. The
+ # exception here is if the string is empty, in which case no
+ # \n should be added
+ first_presplit = first
+ second_presplit = second
+ if first and second:
+ if first[-1] != '\n' or second[-1] != '\n':
+ first_presplit += '\n'
+ second_presplit += '\n'
+ elif second and second[-1] != '\n':
+ second_presplit += '\n'
+ elif first and first[-1] != '\n':
+ first_presplit += '\n'
+
+ firstlines = first_presplit.splitlines(keepends=True)
+ secondlines = second_presplit.splitlines(keepends=True)
+
+ # Generate the message and diff, then raise the exception
standardMsg = '%s != %s' % _common_shorten_repr(first, second)
diff = '\n' + ''.join(difflib.ndiff(firstlines, secondlines))
standardMsg = self._truncateMessage(standardMsg, diff)
diff --git a/Misc/NEWS.d/next/Library/2023-04-27-18-46-31.gh-issue-68968.E3tnhy.rst b/Misc/NEWS.d/next/Library/2023-04-27-18-46-31.gh-issue-68968.E3tnhy.rst
new file mode 100644
index 0000000..bf29b64
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2023-04-27-18-46-31.gh-issue-68968.E3tnhy.rst
@@ -0,0 +1 @@
+Fixed garbled output of :meth:`~unittest.TestCase.assertEqual` when an input lacks final newline.