]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
gh-145546: unittest.util: fix `sorted_list_difference` tail deduplication (GH-145547)
authorStefan Zetzsche <120379523+stefanzetzsche@users.noreply.github.com>
Wed, 11 Mar 2026 12:21:22 +0000 (12:21 +0000)
committerGitHub <noreply@github.com>
Wed, 11 Mar 2026 12:21:22 +0000 (13:21 +0100)
* fix(unittest.util): Deduplicate tail elements in sorted_list_difference

sorted_list_difference failed to deduplicate remaining elements when one
list was exhausted, causing duplicate values in the result.

Deduplicate before extending.

Co-authored-by: blurb-it[bot] <43283697+blurb-it[bot]@users.noreply.github.com>
Lib/test/test_unittest/test_util.py
Lib/unittest/util.py
Misc/NEWS.d/next/Library/2026-03-05-14-13-10.gh-issue-145546.3tnlxx.rst [new file with mode: 0644]

index d590a333930278cb99b0792ee7ea665c82f3138d..09ce09b91b7ac29f9033537451a418a816386f33 100644 (file)
@@ -26,6 +26,39 @@ class TestUtil(unittest.TestCase):
         self.assertEqual(sorted_list_difference([2], [1, 1]), ([2], [1]))
         self.assertEqual(sorted_list_difference([1, 2], [1, 1]), ([2], []))
 
+    def test_sorted_list_difference_tail_deduplication(self):
+        # Tail deduplication when one list is exhausted before the other.
+        # These exercise the except-IndexError path in sorted_list_difference.
+        self.assertEqual(sorted_list_difference([], [0, 0]), ([], [0]))
+        self.assertEqual(sorted_list_difference([0, 0], []), ([0], []))
+        self.assertEqual(sorted_list_difference([], [1, 1, 2, 2]), ([], [1, 2]))
+        self.assertEqual(sorted_list_difference([1, 1, 2, 2], []), ([1, 2], []))
+        # One list exhausts mid-way, leaving duplicated tail in the other.
+        self.assertEqual(sorted_list_difference([1], [1, 2, 2, 3, 3]), ([], [2, 3]))
+        self.assertEqual(sorted_list_difference([1, 2, 2, 3, 3], [1]), ([2, 3], []))
+
+    def test_sorted_list_difference_strings(self):
+        self.assertEqual(
+            sorted_list_difference(['a', 'b'], ['b', 'c']),
+            (['a'], ['c']))
+        self.assertEqual(
+            sorted_list_difference([], ['a', 'a', 'b']),
+            ([], ['a', 'b']))
+        self.assertEqual(
+            sorted_list_difference(['a', 'a', 'b'], []),
+            (['a', 'b'], []))
+
+    def test_sorted_list_difference_unhashable(self):
+        self.assertEqual(
+            sorted_list_difference([[1], [2]], [[2], [3]]),
+            ([[1]], [[3]]))
+        self.assertEqual(
+            sorted_list_difference([], [[0], [0]]),
+            ([], [[0]]))
+        self.assertEqual(
+            sorted_list_difference([[0], [0]], []),
+            ([[0]], []))
+
     def test_unorderable_list_difference(self):
         self.assertEqual(unorderable_list_difference([], []), ([], []))
         self.assertEqual(unorderable_list_difference([1, 2], []), ([2, 1], []))
index c7e6b941978cd5c503821fba728610e0b2fe50eb..0681163c97958700233baf048727a47f1710f062 100644 (file)
@@ -63,6 +63,14 @@ def safe_repr(obj, short=False):
 def strclass(cls):
     return "%s.%s" % (cls.__module__, cls.__qualname__)
 
+def _dedupe_sorted(lst):
+    """Remove consecutive duplicate elements from a sorted list."""
+    result = []
+    for item in lst:
+        if not result or result[-1] != item:
+            result.append(item)
+    return result
+
 def sorted_list_difference(expected, actual):
     """Finds elements in only one or the other of two, sorted input lists.
 
@@ -98,8 +106,8 @@ def sorted_list_difference(expected, actual):
                     while actual[j] == a:
                         j += 1
         except IndexError:
-            missing.extend(expected[i:])
-            unexpected.extend(actual[j:])
+            missing.extend(_dedupe_sorted(expected[i:]))
+            unexpected.extend(_dedupe_sorted(actual[j:]))
             break
     return missing, unexpected
 
diff --git a/Misc/NEWS.d/next/Library/2026-03-05-14-13-10.gh-issue-145546.3tnlxx.rst b/Misc/NEWS.d/next/Library/2026-03-05-14-13-10.gh-issue-145546.3tnlxx.rst
new file mode 100644 (file)
index 0000000..e9401bb
--- /dev/null
@@ -0,0 +1,2 @@
+Fix ``unittest.util.sorted_list_difference()`` to deduplicate remaining
+elements when one input list is exhausted before the other.