mirror of
https://github.com/python/cpython.git
synced 2025-08-03 16:39:00 +00:00

There's no ABC for "PEP 3118 style buffer API objects" because there's no way to recognize these in Python (apart from trying to use memoryview() on them). Note that array.array really should be registered as a MutableSequence but that would require importing it whenever collections is imported.
292 lines
12 KiB
Python
292 lines
12 KiB
Python
"""Unit tests for collections.py."""
|
|
|
|
import unittest
|
|
from test import test_support
|
|
from collections import namedtuple
|
|
from collections import Hashable, Iterable, Iterator
|
|
from collections import Sized, Container, Callable
|
|
from collections import Set, MutableSet
|
|
from collections import Mapping, MutableMapping
|
|
from collections import Sequence, MutableSequence
|
|
from collections import ByteString
|
|
|
|
|
|
class TestNamedTuple(unittest.TestCase):
|
|
|
|
def test_factory(self):
|
|
Point = namedtuple('Point', 'x y')
|
|
self.assertEqual(Point.__name__, 'Point')
|
|
self.assertEqual(Point.__doc__, 'Point(x, y)')
|
|
self.assertEqual(Point.__slots__, ())
|
|
self.assertEqual(Point.__module__, __name__)
|
|
self.assertEqual(Point.__getitem__, tuple.__getitem__)
|
|
|
|
self.assertRaises(ValueError, namedtuple, 'abc%', 'efg ghi') # type has non-alpha char
|
|
self.assertRaises(ValueError, namedtuple, 'class', 'efg ghi') # type has keyword
|
|
self.assertRaises(ValueError, namedtuple, '9abc', 'efg ghi') # type starts with digit
|
|
|
|
self.assertRaises(ValueError, namedtuple, 'abc', 'efg g%hi') # field with non-alpha char
|
|
self.assertRaises(ValueError, namedtuple, 'abc', 'abc class') # field has keyword
|
|
self.assertRaises(ValueError, namedtuple, 'abc', '8efg 9ghi') # field starts with digit
|
|
self.assertRaises(ValueError, namedtuple, 'abc', '__efg__ ghi') # field with double underscores
|
|
self.assertRaises(ValueError, namedtuple, 'abc', 'efg efg ghi') # duplicate field
|
|
|
|
namedtuple('Point0', 'x1 y2') # Verify that numbers are allowed in names
|
|
|
|
def test_instance(self):
|
|
Point = namedtuple('Point', 'x y')
|
|
p = Point(11, 22)
|
|
self.assertEqual(p, Point(x=11, y=22))
|
|
self.assertEqual(p, Point(11, y=22))
|
|
self.assertEqual(p, Point(y=22, x=11))
|
|
self.assertEqual(p, Point(*(11, 22)))
|
|
self.assertEqual(p, Point(**dict(x=11, y=22)))
|
|
self.assertRaises(TypeError, Point, 1) # too few args
|
|
self.assertRaises(TypeError, Point, 1, 2, 3) # too many args
|
|
self.assertRaises(TypeError, eval, 'Point(XXX=1, y=2)', locals()) # wrong keyword argument
|
|
self.assertRaises(TypeError, eval, 'Point(x=1)', locals()) # missing keyword argument
|
|
self.assertEqual(repr(p), 'Point(x=11, y=22)')
|
|
self.assert_('__dict__' not in dir(p)) # verify instance has no dict
|
|
self.assert_('__weakref__' not in dir(p))
|
|
self.assertEqual(p.__fields__, ('x', 'y')) # test __fields__ attribute
|
|
self.assertEqual(p.__replace__(x=1), (1, 22)) # test __replace__ method
|
|
self.assertEqual(p.__asdict__(), dict(x=11, y=22)) # test __dict__ method
|
|
|
|
# Verify that __fields__ is read-only
|
|
try:
|
|
p.__fields__ = ('F1' ,'F2')
|
|
except AttributeError:
|
|
pass
|
|
else:
|
|
self.fail('The __fields__ attribute needs to be read-only')
|
|
|
|
# verify that field string can have commas
|
|
Point = namedtuple('Point', 'x, y')
|
|
p = Point(x=11, y=22)
|
|
self.assertEqual(repr(p), 'Point(x=11, y=22)')
|
|
|
|
# verify that fieldspec can be a non-string sequence
|
|
Point = namedtuple('Point', ('x', 'y'))
|
|
p = Point(x=11, y=22)
|
|
self.assertEqual(repr(p), 'Point(x=11, y=22)')
|
|
|
|
def test_tupleness(self):
|
|
Point = namedtuple('Point', 'x y')
|
|
p = Point(11, 22)
|
|
|
|
self.assert_(isinstance(p, tuple))
|
|
self.assertEqual(p, (11, 22)) # matches a real tuple
|
|
self.assertEqual(tuple(p), (11, 22)) # coercable to a real tuple
|
|
self.assertEqual(list(p), [11, 22]) # coercable to a list
|
|
self.assertEqual(max(p), 22) # iterable
|
|
self.assertEqual(max(*p), 22) # star-able
|
|
x, y = p
|
|
self.assertEqual(p, (x, y)) # unpacks like a tuple
|
|
self.assertEqual((p[0], p[1]), (11, 22)) # indexable like a tuple
|
|
self.assertRaises(IndexError, p.__getitem__, 3)
|
|
|
|
self.assertEqual(p.x, x)
|
|
self.assertEqual(p.y, y)
|
|
self.assertRaises(AttributeError, eval, 'p.z', locals())
|
|
|
|
def test_odd_sizes(self):
|
|
Zero = namedtuple('Zero', '')
|
|
self.assertEqual(Zero(), ())
|
|
Dot = namedtuple('Dot', 'd')
|
|
self.assertEqual(Dot(1), (1,))
|
|
|
|
|
|
class TestOneTrickPonyABCs(unittest.TestCase):
|
|
|
|
def test_Hashable(self):
|
|
# Check some non-hashables
|
|
non_samples = [bytearray(), list(), set(), dict()]
|
|
for x in non_samples:
|
|
self.failIf(isinstance(x, Hashable), repr(x))
|
|
self.failIf(issubclass(type(x), Hashable), repr(type(x)))
|
|
# Check some hashables
|
|
samples = [None,
|
|
int(), float(), complex(),
|
|
str(),
|
|
tuple(), frozenset(),
|
|
int, list, object, type, bytes()
|
|
]
|
|
for x in samples:
|
|
self.failUnless(isinstance(x, Hashable), repr(x))
|
|
self.failUnless(issubclass(type(x), Hashable), repr(type(x)))
|
|
self.assertRaises(TypeError, Hashable)
|
|
# Check direct subclassing
|
|
class H(Hashable):
|
|
def __hash__(self):
|
|
return super().__hash__()
|
|
self.assertEqual(hash(H()), 0)
|
|
self.failIf(issubclass(int, H))
|
|
|
|
def test_Iterable(self):
|
|
# Check some non-iterables
|
|
non_samples = [None, 42, 3.14, 1j]
|
|
for x in non_samples:
|
|
self.failIf(isinstance(x, Iterable), repr(x))
|
|
self.failIf(issubclass(type(x), Iterable), repr(type(x)))
|
|
# Check some iterables
|
|
samples = [bytes(), str(),
|
|
tuple(), list(), set(), frozenset(), dict(),
|
|
dict().keys(), dict().items(), dict().values(),
|
|
(lambda: (yield))(),
|
|
(x for x in []),
|
|
]
|
|
for x in samples:
|
|
self.failUnless(isinstance(x, Iterable), repr(x))
|
|
self.failUnless(issubclass(type(x), Iterable), repr(type(x)))
|
|
# Check direct subclassing
|
|
class I(Iterable):
|
|
def __iter__(self):
|
|
return super().__iter__()
|
|
self.assertEqual(list(I()), [])
|
|
self.failIf(issubclass(str, I))
|
|
|
|
def test_Iterator(self):
|
|
non_samples = [None, 42, 3.14, 1j, b"", "", (), [], {}, set()]
|
|
for x in non_samples:
|
|
self.failIf(isinstance(x, Iterator), repr(x))
|
|
self.failIf(issubclass(type(x), Iterator), repr(type(x)))
|
|
samples = [iter(bytes()), iter(str()),
|
|
iter(tuple()), iter(list()), iter(dict()),
|
|
iter(set()), iter(frozenset()),
|
|
iter(dict().keys()), iter(dict().items()),
|
|
iter(dict().values()),
|
|
(lambda: (yield))(),
|
|
(x for x in []),
|
|
]
|
|
for x in samples:
|
|
self.failUnless(isinstance(x, Iterator), repr(x))
|
|
self.failUnless(issubclass(type(x), Iterator), repr(type(x)))
|
|
|
|
def test_Sized(self):
|
|
non_samples = [None, 42, 3.14, 1j,
|
|
(lambda: (yield))(),
|
|
(x for x in []),
|
|
]
|
|
for x in non_samples:
|
|
self.failIf(isinstance(x, Sized), repr(x))
|
|
self.failIf(issubclass(type(x), Sized), repr(type(x)))
|
|
samples = [bytes(), str(),
|
|
tuple(), list(), set(), frozenset(), dict(),
|
|
dict().keys(), dict().items(), dict().values(),
|
|
]
|
|
for x in samples:
|
|
self.failUnless(isinstance(x, Sized), repr(x))
|
|
self.failUnless(issubclass(type(x), Sized), repr(type(x)))
|
|
|
|
def test_Container(self):
|
|
non_samples = [None, 42, 3.14, 1j,
|
|
(lambda: (yield))(),
|
|
(x for x in []),
|
|
]
|
|
for x in non_samples:
|
|
self.failIf(isinstance(x, Container), repr(x))
|
|
self.failIf(issubclass(type(x), Container), repr(type(x)))
|
|
samples = [bytes(), str(),
|
|
tuple(), list(), set(), frozenset(), dict(),
|
|
dict().keys(), dict().items(),
|
|
]
|
|
for x in samples:
|
|
self.failUnless(isinstance(x, Container), repr(x))
|
|
self.failUnless(issubclass(type(x), Container), repr(type(x)))
|
|
|
|
def test_Callable(self):
|
|
non_samples = [None, 42, 3.14, 1j,
|
|
"", b"", (), [], {}, set(),
|
|
(lambda: (yield))(),
|
|
(x for x in []),
|
|
]
|
|
for x in non_samples:
|
|
self.failIf(isinstance(x, Callable), repr(x))
|
|
self.failIf(issubclass(type(x), Callable), repr(type(x)))
|
|
samples = [lambda: None,
|
|
type, int, object,
|
|
len,
|
|
list.append, [].append,
|
|
]
|
|
for x in samples:
|
|
self.failUnless(isinstance(x, Callable), repr(x))
|
|
self.failUnless(issubclass(type(x), Callable), repr(type(x)))
|
|
|
|
def test_direct_subclassing(self):
|
|
for B in Hashable, Iterable, Iterator, Sized, Container, Callable:
|
|
class C(B):
|
|
pass
|
|
self.failUnless(issubclass(C, B))
|
|
self.failIf(issubclass(int, C))
|
|
|
|
def test_registration(self):
|
|
for B in Hashable, Iterable, Iterator, Sized, Container, Callable:
|
|
class C:
|
|
__hash__ = None # Make sure it isn't hashable by default
|
|
self.failIf(issubclass(C, B), B.__name__)
|
|
B.register(C)
|
|
self.failUnless(issubclass(C, B))
|
|
|
|
|
|
class TestCollectionABCs(unittest.TestCase):
|
|
|
|
# XXX For now, we only test some virtual inheritance properties.
|
|
# We should also test the proper behavior of the collection ABCs
|
|
# as real base classes or mix-in classes.
|
|
|
|
def test_Set(self):
|
|
for sample in [set, frozenset]:
|
|
self.failUnless(isinstance(sample(), Set))
|
|
self.failUnless(issubclass(sample, Set))
|
|
|
|
def test_MutableSet(self):
|
|
self.failUnless(isinstance(set(), MutableSet))
|
|
self.failUnless(issubclass(set, MutableSet))
|
|
self.failIf(isinstance(frozenset(), MutableSet))
|
|
self.failIf(issubclass(frozenset, MutableSet))
|
|
|
|
def test_Mapping(self):
|
|
for sample in [dict]:
|
|
self.failUnless(isinstance(sample(), Mapping))
|
|
self.failUnless(issubclass(sample, Mapping))
|
|
|
|
def test_MutableMapping(self):
|
|
for sample in [dict]:
|
|
self.failUnless(isinstance(sample(), MutableMapping))
|
|
self.failUnless(issubclass(sample, MutableMapping))
|
|
|
|
def test_Sequence(self):
|
|
for sample in [tuple, list, bytes, str]:
|
|
self.failUnless(isinstance(sample(), Sequence))
|
|
self.failUnless(issubclass(sample, Sequence))
|
|
self.failUnless(issubclass(str, Sequence))
|
|
|
|
def test_ByteString(self):
|
|
for sample in [bytes, bytearray]:
|
|
self.failUnless(isinstance(sample(), ByteString))
|
|
self.failUnless(issubclass(sample, ByteString))
|
|
for sample in [str, list, tuple]:
|
|
self.failIf(isinstance(sample(), ByteString))
|
|
self.failIf(issubclass(sample, ByteString))
|
|
self.failIf(isinstance(memoryview(b""), ByteString))
|
|
self.failIf(issubclass(memoryview, ByteString))
|
|
|
|
def test_MutableSequence(self):
|
|
for sample in [tuple, str, bytes]:
|
|
self.failIf(isinstance(sample(), MutableSequence))
|
|
self.failIf(issubclass(sample, MutableSequence))
|
|
for sample in [list, bytearray]:
|
|
self.failUnless(isinstance(sample(), MutableSequence))
|
|
self.failUnless(issubclass(sample, MutableSequence))
|
|
self.failIf(issubclass(str, MutableSequence))
|
|
|
|
|
|
def test_main(verbose=None):
|
|
import collections as CollectionsModule
|
|
test_classes = [TestNamedTuple, TestOneTrickPonyABCs, TestCollectionABCs]
|
|
test_support.run_unittest(*test_classes)
|
|
test_support.run_doctest(CollectionsModule, verbose)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
test_main(verbose=True)
|