Issue 10242. Switching unittest.TestCase.assertItemsEqual to use a collections.Counter under the hood.

This fixes bugs when comparing collections of items like sets that can be sorted without raising an exception but where sorting has no meaning.
This commit is contained in:
Michael Foord 2010-12-19 15:52:56 +00:00
parent a17f076f61
commit e6e0e26780
3 changed files with 22 additions and 14 deletions

View File

@ -1,5 +1,6 @@
"""Test case implementation""" """Test case implementation"""
import collections
import sys import sys
import functools import functools
import difflib import difflib
@ -850,14 +851,12 @@ class TestCase(object):
self.fail(self._formatMessage(msg, standardMsg)) self.fail(self._formatMessage(msg, standardMsg))
def assertItemsEqual(self, expected_seq, actual_seq, msg=None): def assertItemsEqual(self, expected_seq, actual_seq, msg=None):
"""An unordered sequence / set specific comparison. It asserts that """An unordered sequence specific comparison. It asserts that
expected_seq and actual_seq contain the same elements. It is actual_seq and expected_seq have the same element counts.
the equivalent of:: Equivalent to::
self.assertEqual(sorted(expected_seq), sorted(actual_seq)) self.assertEqual(Counter(iter(actual_seq)),
Counter(iter(expected_seq)))
Raises with an error message listing which elements of expected_seq
are missing from actual_seq and vice versa if any.
Asserts that each element has the same count in both sequences. Asserts that each element has the same count in both sequences.
Example: Example:
@ -872,17 +871,18 @@ class TestCase(object):
"comparing unequal types"]: "comparing unequal types"]:
warnings.filterwarnings("ignore", _msg, DeprecationWarning) warnings.filterwarnings("ignore", _msg, DeprecationWarning)
try: try:
expected = sorted(expected_seq) actual = collections.Counter(iter(actual_seq))
actual = sorted(actual_seq) expected = collections.Counter(iter(expected_seq))
except TypeError: except TypeError:
# Unsortable items (example: set(), complex(), ...) # Unsortable items (example: set(), complex(), ...)
expected = list(expected_seq)
actual = list(actual_seq) actual = list(actual_seq)
missing, unexpected = unorderable_list_difference( expected = list(expected_seq)
expected, actual, ignore_duplicate=False missing, unexpected = unorderable_list_difference(expected, actual)
)
else: else:
return self.assertSequenceEqual(expected, actual, msg=msg) if actual == expected:
return
missing = list(expected - actual)
unexpected = list(actual - expected)
errors = [] errors = []
if missing: if missing:

View File

@ -711,6 +711,11 @@ class Test_TestCase(unittest.TestCase, TestEquality, TestHashing):
self.assertRaises(self.failureException, self.assertItemsEqual, self.assertRaises(self.failureException, self.assertItemsEqual,
[1, {'b': 2}, None, True], [{'b': 2}, True, None]) [1, {'b': 2}, None, True], [{'b': 2}, True, None])
# Same elements which don't reliably compare, in
# different order, see issue 10242
a = [{2,4}, {1,2}]
b = a[::-1]
self.assertItemsEqual(a, b)
def testAssertSetEqual(self): def testAssertSetEqual(self):
set1 = set() set1 = set()

View File

@ -22,6 +22,9 @@ Core and Builtins
Library Library
------- -------
- Issue #10242: unittest.TestCase.assertItemsEqual makes too many assumgptions
about input.
- Issue #10611: SystemExit should not cause a unittest test run to exit. - Issue #10611: SystemExit should not cause a unittest test run to exit.
- Issue #6791: Limit header line length (to 65535 bytes) in http.client, - Issue #6791: Limit header line length (to 65535 bytes) in http.client,