[Python-checkins] r87471 - in python/branches/py3k/Lib/unittest: case.py test/test_assertions.py util.py

raymond.hettinger python-checkins at python.org
Fri Dec 24 11:02:22 CET 2010


Author: raymond.hettinger
Date: Fri Dec 24 11:02:22 2010
New Revision: 87471

Log:
Improve diff for assertCountEqual() to actually show the differing counts.

New output looks like this: 

Traceback (most recent call last):
  File "test.py", line 5, in test_ce
    self.assertCountEqual('abracadabra xx', 'simsalabim xx')
AssertionError: Element counts were not equal:
Expected 5, got 2:  'a'
Expected 2, got 1:  'b'
Expected 0, got 2:  'i'
Expected 0, got 2:  'm'
Expected 0, got 1:  'l'
Expected 0, got 2:  's'
Expected 1, got 0:  'c'
Expected 1, got 0:  'd'
Expected 2, got 0:  'r'




Modified:
   python/branches/py3k/Lib/unittest/case.py
   python/branches/py3k/Lib/unittest/test/test_assertions.py
   python/branches/py3k/Lib/unittest/util.py

Modified: python/branches/py3k/Lib/unittest/case.py
==============================================================================
--- python/branches/py3k/Lib/unittest/case.py	(original)
+++ python/branches/py3k/Lib/unittest/case.py	Fri Dec 24 11:02:22 2010
@@ -10,7 +10,8 @@
 
 from . import result
 from .util import (strclass, safe_repr, sorted_list_difference,
-                   unorderable_list_difference)
+                   unorderable_list_difference, _count_diff_all_purpose,
+                   _count_diff_hashable)
 
 __unittest = True
 
@@ -1022,23 +1023,22 @@
             expected = collections.Counter(expected_seq)
         except TypeError:
             # Handle case with unhashable elements
-            missing, unexpected = unorderable_list_difference(expected_seq, actual_seq)
+            differences = _count_diff_all_purpose(expected_seq, actual_seq)
         else:
             if actual == expected:
                 return
-            missing = list(expected - actual)
-            unexpected = list(actual - expected)
+            differences = _count_diff_hashable(expected_seq, actual_seq)
 
-        errors = []
-        if missing:
-            errors.append('Expected, but missing:\n    %s' %
-                           safe_repr(missing))
-        if unexpected:
-            errors.append('Unexpected, but present:\n    %s' %
-                           safe_repr(unexpected))
-        if errors:
-            standardMsg = '\n'.join(errors)
-            self.fail(self._formatMessage(msg, standardMsg))
+        if differences:
+            standardMsg = 'Element counts were not equal:\n'
+            lines = []
+            for act, exp, elem in differences:
+                line = 'Expected %d, got %d:  %r' % (exp, act, elem)
+                lines.append(line)
+            diffMsg = '\n'.join(lines)
+            standardMsg = self._truncateMessage(standardMsg, diffMsg)
+            msg = self._formatMessage(msg, standardMsg)
+            self.fail(msg)
 
     def assertMultiLineEqual(self, first, second, msg=None):
         """Assert that two multi-line strings are equal."""

Modified: python/branches/py3k/Lib/unittest/test/test_assertions.py
==============================================================================
--- python/branches/py3k/Lib/unittest/test/test_assertions.py	(original)
+++ python/branches/py3k/Lib/unittest/test/test_assertions.py	Fri Dec 24 11:02:22 2010
@@ -229,12 +229,6 @@
                              "^Missing: 'key'$",
                              "^Missing: 'key' : oops$"])
 
-    def testassertCountEqual(self):
-        self.assertMessages('assertCountEqual', ([], [None]),
-                            [r"\[None\]$", "^oops$",
-                             r"\[None\]$",
-                             r"\[None\] : oops$"])
-
     def testAssertMultiLineEqual(self):
         self.assertMessages('assertMultiLineEqual', ("", "foo"),
                             [r"\+ foo$", "^oops$",

Modified: python/branches/py3k/Lib/unittest/util.py
==============================================================================
--- python/branches/py3k/Lib/unittest/util.py	(original)
+++ python/branches/py3k/Lib/unittest/util.py	Fri Dec 24 11:02:22 2010
@@ -1,5 +1,7 @@
 """Various utility functions."""
 
+from collections import namedtuple, Counter
+
 __unittest = True
 
 _MAX_LENGTH = 80
@@ -12,7 +14,6 @@
         return result
     return result[:_MAX_LENGTH] + ' [truncated]...'
 
-
 def strclass(cls):
     return "%s.%s" % (cls.__module__, cls.__name__)
 
@@ -77,3 +78,58 @@
 def three_way_cmp(x, y):
     """Return -1 if x < y, 0 if x == y and 1 if x > y"""
     return (x > y) - (x < y)
+
+_Mismatch = namedtuple('Mismatch', 'actual expected value')
+
+def _count_diff_all_purpose(actual, expected):
+    'Returns list of (cnt_act, cnt_exp, elem) triples where the counts differ'
+    # elements need not be hashable
+    s, t = list(actual), list(expected)
+    m, n = len(s), len(t)
+    NULL = object()
+    result = []
+    for i, elem in enumerate(s):
+        if elem is NULL:
+            continue
+        cnt_s = cnt_t = 0
+        for j in range(i, m):
+            if s[j] == elem:
+                cnt_s += 1
+                s[j] = NULL
+        for j, other_elem in enumerate(t):
+            if other_elem == elem:
+                cnt_t += 1
+                t[j] = NULL
+        if cnt_s != cnt_t:
+            diff = _Mismatch(cnt_s, cnt_t, elem)
+            result.append(diff)
+
+    for i, elem in enumerate(t):
+        if elem is NULL:
+            continue
+        cnt_t = 0
+        for j in range(i, n):
+            if t[j] == elem:
+                cnt_t += 1
+                t[j] = NULL
+        diff = _Mismatch(0, cnt_t, elem)
+        result.append(diff)
+    return result
+
+def _count_diff_hashable(actual, expected):
+    'Returns list of (cnt_act, cnt_exp, elem) triples where the counts differ'
+    # elements must be hashable
+    s, t = Counter(actual), Counter(expected)
+    if s == t:
+        return []
+    result = []
+    for elem, cnt_s in s.items():
+        cnt_t = t[elem]
+        if cnt_s != cnt_t:
+            diff = _Mismatch(cnt_s, cnt_t, elem)
+            result.append(diff)
+    for elem, cnt_t in t.items():
+        if elem not in s:
+            diff = _Mismatch(0, cnt_t, elem)
+            result.append(diff)
+    return result


More information about the Python-checkins mailing list