import unittest from test.support import import_helper # Skip this test if the _testcapi, _testlimitedcapi or _testinternalcapi # modules aren't available. _testcapi = import_helper.import_module('_testcapi') _testlimitedcapi = import_helper.import_module('_testlimitedcapi') _testinternalcapi = import_helper.import_module('_testinternalcapi') class set_subclass(set): pass class frozenset_subclass(frozenset): pass class BaseSetTests: def assertImmutable(self, action, *args): self.assertRaises(SystemError, action, frozenset(), *args) self.assertRaises(SystemError, action, frozenset({1}), *args) self.assertRaises(SystemError, action, frozenset_subclass(), *args) self.assertRaises(SystemError, action, frozenset_subclass({1}), *args) class TestSetCAPI(BaseSetTests, unittest.TestCase): def test_set_check(self): check = _testlimitedcapi.set_check self.assertTrue(check(set())) self.assertTrue(check({1, 2})) self.assertFalse(check(frozenset())) self.assertTrue(check(set_subclass())) self.assertFalse(check(frozenset_subclass())) self.assertFalse(check(object())) # CRASHES: check(NULL) def test_set_check_exact(self): check = _testlimitedcapi.set_checkexact self.assertTrue(check(set())) self.assertTrue(check({1, 2})) self.assertFalse(check(frozenset())) self.assertFalse(check(set_subclass())) self.assertFalse(check(frozenset_subclass())) self.assertFalse(check(object())) # CRASHES: check(NULL) def test_frozenset_check(self): check = _testlimitedcapi.frozenset_check self.assertFalse(check(set())) self.assertTrue(check(frozenset())) self.assertTrue(check(frozenset({1, 2}))) self.assertFalse(check(set_subclass())) self.assertTrue(check(frozenset_subclass())) self.assertFalse(check(object())) # CRASHES: check(NULL) def test_frozenset_check_exact(self): check = _testlimitedcapi.frozenset_checkexact self.assertFalse(check(set())) self.assertTrue(check(frozenset())) self.assertTrue(check(frozenset({1, 2}))) self.assertFalse(check(set_subclass())) self.assertFalse(check(frozenset_subclass())) self.assertFalse(check(object())) # CRASHES: check(NULL) def test_anyset_check(self): check = _testlimitedcapi.anyset_check self.assertTrue(check(set())) self.assertTrue(check({1, 2})) self.assertTrue(check(frozenset())) self.assertTrue(check(frozenset({1, 2}))) self.assertTrue(check(set_subclass())) self.assertTrue(check(frozenset_subclass())) self.assertFalse(check(object())) # CRASHES: check(NULL) def test_anyset_check_exact(self): check = _testlimitedcapi.anyset_checkexact self.assertTrue(check(set())) self.assertTrue(check({1, 2})) self.assertTrue(check(frozenset())) self.assertTrue(check(frozenset({1, 2}))) self.assertFalse(check(set_subclass())) self.assertFalse(check(frozenset_subclass())) self.assertFalse(check(object())) # CRASHES: check(NULL) def test_set_new(self): set_new = _testlimitedcapi.set_new self.assertEqual(set_new().__class__, set) self.assertEqual(set_new(), set()) self.assertEqual(set_new((1, 1, 2)), {1, 2}) self.assertEqual(set_new([1, 1, 2]), {1, 2}) with self.assertRaisesRegex(TypeError, 'object is not iterable'): set_new(object()) with self.assertRaisesRegex(TypeError, 'object is not iterable'): set_new(1) with self.assertRaisesRegex(TypeError, "unhashable type: 'dict'"): set_new((1, {})) def test_frozenset_new(self): frozenset_new = _testlimitedcapi.frozenset_new self.assertEqual(frozenset_new().__class__, frozenset) self.assertEqual(frozenset_new(), frozenset()) self.assertEqual(frozenset_new((1, 1, 2)), frozenset({1, 2})) self.assertEqual(frozenset_new([1, 1, 2]), frozenset({1, 2})) with self.assertRaisesRegex(TypeError, 'object is not iterable'): frozenset_new(object()) with self.assertRaisesRegex(TypeError, 'object is not iterable'): frozenset_new(1) with self.assertRaisesRegex(TypeError, "unhashable type: 'dict'"): frozenset_new((1, {})) def test_set_size(self): get_size = _testlimitedcapi.set_size self.assertEqual(get_size(set()), 0) self.assertEqual(get_size(frozenset()), 0) self.assertEqual(get_size({1, 1, 2}), 2) self.assertEqual(get_size(frozenset({1, 1, 2})), 2) self.assertEqual(get_size(set_subclass((1, 2, 3))), 3) self.assertEqual(get_size(frozenset_subclass((1, 2, 3))), 3) with self.assertRaises(SystemError): get_size(object()) # CRASHES: get_size(NULL) def test_set_get_size(self): get_size = _testcapi.set_get_size self.assertEqual(get_size(set()), 0) self.assertEqual(get_size(frozenset()), 0) self.assertEqual(get_size({1, 1, 2}), 2) self.assertEqual(get_size(frozenset({1, 1, 2})), 2) self.assertEqual(get_size(set_subclass((1, 2, 3))), 3) self.assertEqual(get_size(frozenset_subclass((1, 2, 3))), 3) # CRASHES: get_size(NULL) # CRASHES: get_size(object()) def test_set_contains(self): contains = _testlimitedcapi.set_contains for cls in (set, frozenset, set_subclass, frozenset_subclass): with self.subTest(cls=cls): instance = cls((1, 2)) self.assertTrue(contains(instance, 1)) self.assertFalse(contains(instance, 'missing')) with self.assertRaisesRegex(TypeError, "unhashable type: 'list'"): contains(instance, []) # CRASHES: contains(instance, NULL) # CRASHES: contains(NULL, object()) # CRASHES: contains(NULL, NULL) def test_add(self): add = _testlimitedcapi.set_add for cls in (set, set_subclass): with self.subTest(cls=cls): instance = cls((1, 2)) self.assertEqual(add(instance, 1), 0) self.assertEqual(instance, {1, 2}) self.assertEqual(add(instance, 3), 0) self.assertEqual(instance, {1, 2, 3}) with self.assertRaisesRegex(TypeError, "unhashable type: 'list'"): add(instance, []) with self.assertRaises(SystemError): add(object(), 1) self.assertImmutable(add, 1) # CRASHES: add(NULL, object()) # CRASHES: add(instance, NULL) # CRASHES: add(NULL, NULL) def test_discard(self): discard = _testlimitedcapi.set_discard for cls in (set, set_subclass): with self.subTest(cls=cls): instance = cls((1, 2)) self.assertEqual(discard(instance, 3), 0) self.assertEqual(instance, {1, 2}) self.assertEqual(discard(instance, 1), 1) self.assertEqual(instance, {2}) self.assertEqual(discard(instance, 2), 1) self.assertEqual(instance, set()) self.assertEqual(discard(instance, 2), 0) self.assertEqual(instance, set()) with self.assertRaisesRegex(TypeError, "unhashable type: 'list'"): discard(instance, []) with self.assertRaises(SystemError): discard(object(), 1) self.assertImmutable(discard, 1) # CRASHES: discard(NULL, object()) # CRASHES: discard(instance, NULL) # CRASHES: discard(NULL, NULL) def test_pop(self): pop = _testlimitedcapi.set_pop orig = (1, 2) for cls in (set, set_subclass): with self.subTest(cls=cls): instance = cls(orig) self.assertIn(pop(instance), orig) self.assertEqual(len(instance), 1) self.assertIn(pop(instance), orig) self.assertEqual(len(instance), 0) with self.assertRaises(KeyError): pop(instance) with self.assertRaises(SystemError): pop(object()) self.assertImmutable(pop) # CRASHES: pop(NULL) def test_clear(self): clear = _testlimitedcapi.set_clear for cls in (set, set_subclass): with self.subTest(cls=cls): instance = cls((1, 2)) self.assertEqual(clear(instance), 0) self.assertEqual(instance, set()) self.assertEqual(clear(instance), 0) self.assertEqual(instance, set()) with self.assertRaises(SystemError): clear(object()) self.assertImmutable(clear) # CRASHES: clear(NULL) class TestInternalCAPI(BaseSetTests, unittest.TestCase): def test_set_update(self): update = _testinternalcapi.set_update for cls in (set, set_subclass): for it in ('ab', ('a', 'b'), ['a', 'b'], set('ab'), set_subclass('ab'), frozenset('ab'), frozenset_subclass('ab')): with self.subTest(cls=cls, it=it): instance = cls() self.assertEqual(update(instance, it), 0) self.assertEqual(instance, {'a', 'b'}) instance = cls(it) self.assertEqual(update(instance, it), 0) self.assertEqual(instance, {'a', 'b'}) with self.assertRaisesRegex(TypeError, 'object is not iterable'): update(cls(), 1) with self.assertRaisesRegex(TypeError, "unhashable type: 'dict'"): update(cls(), [{}]) with self.assertRaises(SystemError): update(object(), 'ab') self.assertImmutable(update, 'ab') # CRASHES: update(NULL, object()) # CRASHES: update(instance, NULL) # CRASHES: update(NULL, NULL) def test_set_next_entry(self): set_next = _testinternalcapi.set_next_entry for cls in (set, set_subclass, frozenset, frozenset_subclass): with self.subTest(cls=cls): instance = cls('abc') pos = 0 items = [] while True: res = set_next(instance, pos) if res is None: break rc, pos, hash_, item = res items.append(item) self.assertEqual(rc, 1) self.assertIn(item, instance) self.assertEqual(hash(item), hash_) self.assertEqual(items, list(instance)) with self.assertRaises(SystemError): set_next(object(), 0) # CRASHES: set_next(NULL, 0)