Index: Lib/unittest/case.py =================================================================== --- Lib/unittest/case.py (revision 77910) +++ Lib/unittest/case.py (working copy) @@ -516,7 +516,7 @@ msg: Optional message to use on failure instead of a list of differences. """ - if seq_type != None: + if seq_type is not None: seq_type_name = seq_type.__name__ if not isinstance(seq1, seq_type): raise self.failureException('First sequence is not a %s: %r' @@ -729,32 +729,24 @@ self.fail(self._formatMessage(msg, standardMsg)) def assertSameElements(self, expected_seq, actual_seq, msg=None): - """An unordered sequence specific comparison. + """An unordered sequence/set specific comparison. Raises with an error message listing which elements of expected_seq are missing from actual_seq and vice versa if any. + Example: + - [1, 0] and [0, 0, 1] and [True, False] compare equal. """ try: expected = set(expected_seq) actual = set(actual_seq) - missing = list(expected.difference(actual)) - unexpected = list(actual.difference(expected)) - missing.sort() - unexpected.sort() + missing = sorted(expected.difference(actual), key=util.SafeKey) + unexpected = sorted(actual.difference(expected), key=util.SafeKey) except TypeError: # Fall back to slower list-compare if any of the objects are # not hashable. - expected = list(expected_seq) - actual = list(actual_seq) - with warnings.catch_warnings(): - if sys.py3kwarning: - # Silence Py3k warning - warnings.filterwarnings("ignore", - "dict inequality comparisons " - "not supported", DeprecationWarning) - expected.sort() - actual.sort() - missing, unexpected = util.sorted_list_difference(expected, actual) + expected = sorted(expected_seq, key=util.SafeKey) + actual = sorted(actual_seq, key=util.SafeKey) + missing, unexpected = util.sorted_list_difference(expected, actual) errors = [] if missing: errors.append('Expected, but missing:\n %r' % missing) Index: Lib/unittest/util.py =================================================================== --- Lib/unittest/util.py (revision 77910) +++ Lib/unittest/util.py (working copy) @@ -3,6 +3,16 @@ def strclass(cls): return "%s.%s" % (cls.__module__, cls.__name__) +class SafeKey(object): + """ + Helper class for key functions when sorting unorderable objects. + """ + def __init__(self, obj): + self.obj = obj + + def __lt__(self, other): + return cmp(self.obj, other.obj) == -1 + def sorted_list_difference(expected, actual): """Finds elements in only one or the other of two, sorted input lists. @@ -18,12 +28,12 @@ try: e = expected[i] a = actual[j] - if e < a: + if SafeKey(e) < SafeKey(a): missing.append(e) i += 1 while expected[i] == e: i += 1 - elif e > a: + elif SafeKey(e) > SafeKey(a): unexpected.append(a) j += 1 while actual[j] == a: Index: Lib/test/test_unittest.py =================================================================== --- Lib/test/test_unittest.py (revision 77910) +++ Lib/test/test_unittest.py (working copy) @@ -2482,9 +2482,9 @@ class SadSnake(object): """Dummy class for test_addTypeEqualityFunc.""" s1, s2 = SadSnake(), SadSnake() - self.assertFalse(s1 == s2) + self.assertNotEqual(s1, s2) def AllSnakesCreatedEqual(a, b, msg=None): - return type(a) == type(b) == SadSnake + return type(a) is type(b) is SadSnake self.addTypeEqualityFunc(SadSnake, AllSnakesCreatedEqual) self.assertEqual(s1, s2) # No this doesn't clean up and remove the SadSnake equality func @@ -2646,21 +2646,29 @@ self.assertRaises(self.failureException, self.assertDictEqual, [], d) self.assertRaises(self.failureException, self.assertDictEqual, 1, 1) + # Compare sets of elements self.assertSameElements([1, 2, 3], [3, 2, 1]) self.assertSameElements([1, 2] + [3] * 100, [1] * 100 + [2, 3]) self.assertSameElements(['foo', 'bar', 'baz'], ['bar', 'baz', 'foo']) + self.assertSameElements([a, a, 2, 2, 3], (a, 2, 3, a, 2)) + self.assertSameElements([1, "2", "a", "a"], ["a", "2", True, 1]) self.assertRaises(self.failureException, self.assertSameElements, [10], [10, 11]) self.assertRaises(self.failureException, self.assertSameElements, [10, 11], [10]) # Test that sequences of unhashable objects can be tested for sameness: - self.assertSameElements([[1, 2], [3, 4]], [[3, 4], [1, 2]]) + self.assertSameElements([0, [1, 2], [3, 4]], [[3, 4], False, [1, 2]]) self.assertSameElements([{'a': 1}, {'b': 2}], [{'b': 2}, {'a': 1}]) self.assertRaises(self.failureException, self.assertSameElements, [[1]], [[2]]) + # Same elements, but not same sequence length + self.assertSameElements([1, 1, 2], [2, 1]) + self.assertSameElements([1, 1, "2", "a", "a"], ["2", "2", True, "a"]) + self.assertSameElements([1, {'b': 2}, None, True], [{'b': 2}, True, None]) + def testAssertSetEqual(self): set1 = set() set2 = set() @@ -2909,13 +2917,14 @@ Do not use these methods. They will go away in 3.3. """ - self.failIfEqual(3, 5) - self.failUnlessEqual(3, 3) - self.failUnlessAlmostEqual(2.0, 2.0) - self.failIfAlmostEqual(3.0, 5.0) - self.failUnless(True) - self.failUnlessRaises(TypeError, lambda _: 3.14 + u'spam') - self.failIf(False) + with test_support.check_warnings(): + self.failIfEqual(3, 5) + self.failUnlessEqual(3, 3) + self.failUnlessAlmostEqual(2.0, 2.0) + self.failIfAlmostEqual(3.0, 5.0) + self.failUnless(True) + self.failUnlessRaises(TypeError, lambda _: 3.14 + u'spam') + self.failIf(False) def testDeepcopy(self): # Issue: 5660 @@ -3056,7 +3065,7 @@ try: self.assertRaises(KeyError, lambda: None) except self.failureException as e: - self.assertIn("KeyError not raised", e) + self.assertIn("KeyError not raised", e.args) else: self.fail("assertRaises() didn't fail") try: @@ -3073,7 +3082,7 @@ with self.assertRaises(KeyError): pass except self.failureException as e: - self.assertIn("KeyError not raised", e) + self.assertIn("KeyError not raised", e.args) else: self.fail("assertRaises() didn't fail") try: @@ -3591,6 +3600,9 @@ def __eq__(self, other): return self.path == other.path + # Silence Py3k warning + __hash__ = None + loader._get_module_from_name = lambda name: Module(name) def loadTestsFromModule(module, use_load_tests): if use_load_tests: