1#! /usr/bin/env python
2"""Test the arraymodule.
3   Roger E. Masse
4"""
5
6import unittest
7import warnings
8from test import test_support
9from weakref import proxy
10import array, cStringIO
11from cPickle import loads, dumps, HIGHEST_PROTOCOL
12
13class ArraySubclass(array.array):
14    pass
15
16class ArraySubclassWithKwargs(array.array):
17    def __init__(self, typecode, newarg=None):
18        array.array.__init__(self, typecode)
19
20tests = [] # list to accumulate all tests
21typecodes = "cubBhHiIlLfd"
22
23class BadConstructorTest(unittest.TestCase):
24
25    def test_constructor(self):
26        self.assertRaises(TypeError, array.array)
27        self.assertRaises(TypeError, array.array, spam=42)
28        self.assertRaises(TypeError, array.array, 'xx')
29        self.assertRaises(ValueError, array.array, 'x')
30
31tests.append(BadConstructorTest)
32
33class BaseTest(unittest.TestCase):
34    # Required class attributes (provided by subclasses
35    # typecode: the typecode to test
36    # example: an initializer usable in the constructor for this type
37    # smallerexample: the same length as example, but smaller
38    # biggerexample: the same length as example, but bigger
39    # outside: An entry that is not in example
40    # minitemsize: the minimum guaranteed itemsize
41
42    def assertEntryEqual(self, entry1, entry2):
43        self.assertEqual(entry1, entry2)
44
45    def badtypecode(self):
46        # Return a typecode that is different from our own
47        return typecodes[(typecodes.index(self.typecode)+1) % len(typecodes)]
48
49    def test_constructor(self):
50        a = array.array(self.typecode)
51        self.assertEqual(a.typecode, self.typecode)
52        self.assertTrue(a.itemsize>=self.minitemsize)
53        self.assertRaises(TypeError, array.array, self.typecode, None)
54
55    def test_len(self):
56        a = array.array(self.typecode)
57        a.append(self.example[0])
58        self.assertEqual(len(a), 1)
59
60        a = array.array(self.typecode, self.example)
61        self.assertEqual(len(a), len(self.example))
62
63    def test_buffer_info(self):
64        a = array.array(self.typecode, self.example)
65        self.assertRaises(TypeError, a.buffer_info, 42)
66        bi = a.buffer_info()
67        self.assertIsInstance(bi, tuple)
68        self.assertEqual(len(bi), 2)
69        self.assertIsInstance(bi[0], (int, long))
70        self.assertIsInstance(bi[1], int)
71        self.assertEqual(bi[1], len(a))
72
73    def test_byteswap(self):
74        a = array.array(self.typecode, self.example)
75        self.assertRaises(TypeError, a.byteswap, 42)
76        if a.itemsize in (1, 2, 4, 8):
77            b = array.array(self.typecode, self.example)
78            b.byteswap()
79            if a.itemsize==1:
80                self.assertEqual(a, b)
81            else:
82                self.assertNotEqual(a, b)
83            b.byteswap()
84            self.assertEqual(a, b)
85
86    def test_copy(self):
87        import copy
88        a = array.array(self.typecode, self.example)
89        b = copy.copy(a)
90        self.assertNotEqual(id(a), id(b))
91        self.assertEqual(a, b)
92
93    def test_deepcopy(self):
94        import copy
95        a = array.array(self.typecode, self.example)
96        b = copy.deepcopy(a)
97        self.assertNotEqual(id(a), id(b))
98        self.assertEqual(a, b)
99
100    def test_pickle(self):
101        for protocol in range(HIGHEST_PROTOCOL + 1):
102            a = array.array(self.typecode, self.example)
103            b = loads(dumps(a, protocol))
104            self.assertNotEqual(id(a), id(b))
105            self.assertEqual(a, b)
106
107            a = ArraySubclass(self.typecode, self.example)
108            a.x = 10
109            b = loads(dumps(a, protocol))
110            self.assertNotEqual(id(a), id(b))
111            self.assertEqual(a, b)
112            self.assertEqual(a.x, b.x)
113            self.assertEqual(type(a), type(b))
114
115    def test_pickle_for_empty_array(self):
116        for protocol in range(HIGHEST_PROTOCOL + 1):
117            a = array.array(self.typecode)
118            b = loads(dumps(a, protocol))
119            self.assertNotEqual(id(a), id(b))
120            self.assertEqual(a, b)
121
122            a = ArraySubclass(self.typecode)
123            a.x = 10
124            b = loads(dumps(a, protocol))
125            self.assertNotEqual(id(a), id(b))
126            self.assertEqual(a, b)
127            self.assertEqual(a.x, b.x)
128            self.assertEqual(type(a), type(b))
129
130    def test_insert(self):
131        a = array.array(self.typecode, self.example)
132        a.insert(0, self.example[0])
133        self.assertEqual(len(a), 1+len(self.example))
134        self.assertEqual(a[0], a[1])
135        self.assertRaises(TypeError, a.insert)
136        self.assertRaises(TypeError, a.insert, None)
137        self.assertRaises(TypeError, a.insert, 0, None)
138
139        a = array.array(self.typecode, self.example)
140        a.insert(-1, self.example[0])
141        self.assertEqual(
142            a,
143            array.array(
144                self.typecode,
145                self.example[:-1] + self.example[:1] + self.example[-1:]
146            )
147        )
148
149        a = array.array(self.typecode, self.example)
150        a.insert(-1000, self.example[0])
151        self.assertEqual(
152            a,
153            array.array(self.typecode, self.example[:1] + self.example)
154        )
155
156        a = array.array(self.typecode, self.example)
157        a.insert(1000, self.example[0])
158        self.assertEqual(
159            a,
160            array.array(self.typecode, self.example + self.example[:1])
161        )
162
163    def test_tofromfile(self):
164        a = array.array(self.typecode, 2*self.example)
165        self.assertRaises(TypeError, a.tofile)
166        self.assertRaises(TypeError, a.tofile, cStringIO.StringIO())
167        test_support.unlink(test_support.TESTFN)
168        f = open(test_support.TESTFN, 'wb')
169        try:
170            a.tofile(f)
171            f.close()
172            b = array.array(self.typecode)
173            f = open(test_support.TESTFN, 'rb')
174            self.assertRaises(TypeError, b.fromfile)
175            self.assertRaises(
176                TypeError,
177                b.fromfile,
178                cStringIO.StringIO(), len(self.example)
179            )
180            b.fromfile(f, len(self.example))
181            self.assertEqual(b, array.array(self.typecode, self.example))
182            self.assertNotEqual(a, b)
183            b.fromfile(f, len(self.example))
184            self.assertEqual(a, b)
185            self.assertRaises(EOFError, b.fromfile, f, 1)
186            f.close()
187        finally:
188            if not f.closed:
189                f.close()
190            test_support.unlink(test_support.TESTFN)
191
192    def test_fromfile_ioerror(self):
193        # Issue #5395: Check if fromfile raises a proper IOError
194        # instead of EOFError.
195        a = array.array(self.typecode)
196        f = open(test_support.TESTFN, 'wb')
197        try:
198            self.assertRaises(IOError, a.fromfile, f, len(self.example))
199        finally:
200            f.close()
201            test_support.unlink(test_support.TESTFN)
202
203    def test_filewrite(self):
204        a = array.array(self.typecode, 2*self.example)
205        f = open(test_support.TESTFN, 'wb')
206        try:
207            f.write(a)
208            f.close()
209            b = array.array(self.typecode)
210            f = open(test_support.TESTFN, 'rb')
211            b.fromfile(f, len(self.example))
212            self.assertEqual(b, array.array(self.typecode, self.example))
213            self.assertNotEqual(a, b)
214            b.fromfile(f, len(self.example))
215            self.assertEqual(a, b)
216            f.close()
217        finally:
218            if not f.closed:
219                f.close()
220            test_support.unlink(test_support.TESTFN)
221
222    def test_tofromlist(self):
223        a = array.array(self.typecode, 2*self.example)
224        b = array.array(self.typecode)
225        self.assertRaises(TypeError, a.tolist, 42)
226        self.assertRaises(TypeError, b.fromlist)
227        self.assertRaises(TypeError, b.fromlist, 42)
228        self.assertRaises(TypeError, b.fromlist, [None])
229        b.fromlist(a.tolist())
230        self.assertEqual(a, b)
231
232    def test_tofromstring(self):
233        a = array.array(self.typecode, 2*self.example)
234        b = array.array(self.typecode)
235        self.assertRaises(TypeError, a.tostring, 42)
236        self.assertRaises(TypeError, b.fromstring)
237        self.assertRaises(TypeError, b.fromstring, 42)
238        b.fromstring(a.tostring())
239        self.assertEqual(a, b)
240        if a.itemsize>1:
241            self.assertRaises(ValueError, b.fromstring, "x")
242
243    def test_repr(self):
244        a = array.array(self.typecode, 2*self.example)
245        self.assertEqual(a, eval(repr(a), {"array": array.array}))
246
247        a = array.array(self.typecode)
248        self.assertEqual(repr(a), "array('%s')" % self.typecode)
249
250    def test_str(self):
251        a = array.array(self.typecode, 2*self.example)
252        str(a)
253
254    def test_cmp(self):
255        a = array.array(self.typecode, self.example)
256        self.assertTrue((a == 42) is False)
257        self.assertTrue((a != 42) is True)
258
259        self.assertTrue((a == a) is True)
260        self.assertTrue((a != a) is False)
261        self.assertTrue((a < a) is False)
262        self.assertTrue((a <= a) is True)
263        self.assertTrue((a > a) is False)
264        self.assertTrue((a >= a) is True)
265
266        al = array.array(self.typecode, self.smallerexample)
267        ab = array.array(self.typecode, self.biggerexample)
268
269        self.assertTrue((a == 2*a) is False)
270        self.assertTrue((a != 2*a) is True)
271        self.assertTrue((a < 2*a) is True)
272        self.assertTrue((a <= 2*a) is True)
273        self.assertTrue((a > 2*a) is False)
274        self.assertTrue((a >= 2*a) is False)
275
276        self.assertTrue((a == al) is False)
277        self.assertTrue((a != al) is True)
278        self.assertTrue((a < al) is False)
279        self.assertTrue((a <= al) is False)
280        self.assertTrue((a > al) is True)
281        self.assertTrue((a >= al) is True)
282
283        self.assertTrue((a == ab) is False)
284        self.assertTrue((a != ab) is True)
285        self.assertTrue((a < ab) is True)
286        self.assertTrue((a <= ab) is True)
287        self.assertTrue((a > ab) is False)
288        self.assertTrue((a >= ab) is False)
289
290    def test_add(self):
291        a = array.array(self.typecode, self.example) \
292            + array.array(self.typecode, self.example[::-1])
293        self.assertEqual(
294            a,
295            array.array(self.typecode, self.example + self.example[::-1])
296        )
297
298        b = array.array(self.badtypecode())
299        self.assertRaises(TypeError, a.__add__, b)
300
301        self.assertRaises(TypeError, a.__add__, "bad")
302
303    def test_iadd(self):
304        a = array.array(self.typecode, self.example[::-1])
305        b = a
306        a += array.array(self.typecode, 2*self.example)
307        self.assertTrue(a is b)
308        self.assertEqual(
309            a,
310            array.array(self.typecode, self.example[::-1]+2*self.example)
311        )
312        a = array.array(self.typecode, self.example)
313        a += a
314        self.assertEqual(
315            a,
316            array.array(self.typecode, self.example + self.example)
317        )
318
319        b = array.array(self.badtypecode())
320        self.assertRaises(TypeError, a.__add__, b)
321
322        self.assertRaises(TypeError, a.__iadd__, "bad")
323
324    def test_mul(self):
325        a = 5*array.array(self.typecode, self.example)
326        self.assertEqual(
327            a,
328            array.array(self.typecode, 5*self.example)
329        )
330
331        a = array.array(self.typecode, self.example)*5
332        self.assertEqual(
333            a,
334            array.array(self.typecode, self.example*5)
335        )
336
337        a = 0*array.array(self.typecode, self.example)
338        self.assertEqual(
339            a,
340            array.array(self.typecode)
341        )
342
343        a = (-1)*array.array(self.typecode, self.example)
344        self.assertEqual(
345            a,
346            array.array(self.typecode)
347        )
348
349        self.assertRaises(TypeError, a.__mul__, "bad")
350
351    def test_imul(self):
352        a = array.array(self.typecode, self.example)
353        b = a
354
355        a *= 5
356        self.assertTrue(a is b)
357        self.assertEqual(
358            a,
359            array.array(self.typecode, 5*self.example)
360        )
361
362        a *= 0
363        self.assertTrue(a is b)
364        self.assertEqual(a, array.array(self.typecode))
365
366        a *= 1000
367        self.assertTrue(a is b)
368        self.assertEqual(a, array.array(self.typecode))
369
370        a *= -1
371        self.assertTrue(a is b)
372        self.assertEqual(a, array.array(self.typecode))
373
374        a = array.array(self.typecode, self.example)
375        a *= -1
376        self.assertEqual(a, array.array(self.typecode))
377
378        self.assertRaises(TypeError, a.__imul__, "bad")
379
380    def test_getitem(self):
381        a = array.array(self.typecode, self.example)
382        self.assertEntryEqual(a[0], self.example[0])
383        self.assertEntryEqual(a[0L], self.example[0])
384        self.assertEntryEqual(a[-1], self.example[-1])
385        self.assertEntryEqual(a[-1L], self.example[-1])
386        self.assertEntryEqual(a[len(self.example)-1], self.example[-1])
387        self.assertEntryEqual(a[-len(self.example)], self.example[0])
388        self.assertRaises(TypeError, a.__getitem__)
389        self.assertRaises(IndexError, a.__getitem__, len(self.example))
390        self.assertRaises(IndexError, a.__getitem__, -len(self.example)-1)
391
392    def test_setitem(self):
393        a = array.array(self.typecode, self.example)
394        a[0] = a[-1]
395        self.assertEntryEqual(a[0], a[-1])
396
397        a = array.array(self.typecode, self.example)
398        a[0L] = a[-1]
399        self.assertEntryEqual(a[0], a[-1])
400
401        a = array.array(self.typecode, self.example)
402        a[-1] = a[0]
403        self.assertEntryEqual(a[0], a[-1])
404
405        a = array.array(self.typecode, self.example)
406        a[-1L] = a[0]
407        self.assertEntryEqual(a[0], a[-1])
408
409        a = array.array(self.typecode, self.example)
410        a[len(self.example)-1] = a[0]
411        self.assertEntryEqual(a[0], a[-1])
412
413        a = array.array(self.typecode, self.example)
414        a[-len(self.example)] = a[-1]
415        self.assertEntryEqual(a[0], a[-1])
416
417        self.assertRaises(TypeError, a.__setitem__)
418        self.assertRaises(TypeError, a.__setitem__, None)
419        self.assertRaises(TypeError, a.__setitem__, 0, None)
420        self.assertRaises(
421            IndexError,
422            a.__setitem__,
423            len(self.example), self.example[0]
424        )
425        self.assertRaises(
426            IndexError,
427            a.__setitem__,
428            -len(self.example)-1, self.example[0]
429        )
430
431    def test_delitem(self):
432        a = array.array(self.typecode, self.example)
433        del a[0]
434        self.assertEqual(
435            a,
436            array.array(self.typecode, self.example[1:])
437        )
438
439        a = array.array(self.typecode, self.example)
440        del a[-1]
441        self.assertEqual(
442            a,
443            array.array(self.typecode, self.example[:-1])
444        )
445
446        a = array.array(self.typecode, self.example)
447        del a[len(self.example)-1]
448        self.assertEqual(
449            a,
450            array.array(self.typecode, self.example[:-1])
451        )
452
453        a = array.array(self.typecode, self.example)
454        del a[-len(self.example)]
455        self.assertEqual(
456            a,
457            array.array(self.typecode, self.example[1:])
458        )
459
460        self.assertRaises(TypeError, a.__delitem__)
461        self.assertRaises(TypeError, a.__delitem__, None)
462        self.assertRaises(IndexError, a.__delitem__, len(self.example))
463        self.assertRaises(IndexError, a.__delitem__, -len(self.example)-1)
464
465    def test_getslice(self):
466        a = array.array(self.typecode, self.example)
467        self.assertEqual(a[:], a)
468
469        self.assertEqual(
470            a[1:],
471            array.array(self.typecode, self.example[1:])
472        )
473
474        self.assertEqual(
475            a[:1],
476            array.array(self.typecode, self.example[:1])
477        )
478
479        self.assertEqual(
480            a[:-1],
481            array.array(self.typecode, self.example[:-1])
482        )
483
484        self.assertEqual(
485            a[-1:],
486            array.array(self.typecode, self.example[-1:])
487        )
488
489        self.assertEqual(
490            a[-1:-1],
491            array.array(self.typecode)
492        )
493
494        self.assertEqual(
495            a[2:1],
496            array.array(self.typecode)
497        )
498
499        self.assertEqual(
500            a[1000:],
501            array.array(self.typecode)
502        )
503        self.assertEqual(a[-1000:], a)
504        self.assertEqual(a[:1000], a)
505        self.assertEqual(
506            a[:-1000],
507            array.array(self.typecode)
508        )
509        self.assertEqual(a[-1000:1000], a)
510        self.assertEqual(
511            a[2000:1000],
512            array.array(self.typecode)
513        )
514
515    def test_extended_getslice(self):
516        # Test extended slicing by comparing with list slicing
517        # (Assumes list conversion works correctly, too)
518        a = array.array(self.typecode, self.example)
519        indices = (0, None, 1, 3, 19, 100, -1, -2, -31, -100)
520        for start in indices:
521            for stop in indices:
522                # Everything except the initial 0 (invalid step)
523                for step in indices[1:]:
524                    self.assertEqual(list(a[start:stop:step]),
525                                     list(a)[start:stop:step])
526
527    def test_setslice(self):
528        a = array.array(self.typecode, self.example)
529        a[:1] = a
530        self.assertEqual(
531            a,
532            array.array(self.typecode, self.example + self.example[1:])
533        )
534
535        a = array.array(self.typecode, self.example)
536        a[:-1] = a
537        self.assertEqual(
538            a,
539            array.array(self.typecode, self.example + self.example[-1:])
540        )
541
542        a = array.array(self.typecode, self.example)
543        a[-1:] = a
544        self.assertEqual(
545            a,
546            array.array(self.typecode, self.example[:-1] + self.example)
547        )
548
549        a = array.array(self.typecode, self.example)
550        a[1:] = a
551        self.assertEqual(
552            a,
553            array.array(self.typecode, self.example[:1] + self.example)
554        )
555
556        a = array.array(self.typecode, self.example)
557        a[1:-1] = a
558        self.assertEqual(
559            a,
560            array.array(
561                self.typecode,
562                self.example[:1] + self.example + self.example[-1:]
563            )
564        )
565
566        a = array.array(self.typecode, self.example)
567        a[1000:] = a
568        self.assertEqual(
569            a,
570            array.array(self.typecode, 2*self.example)
571        )
572
573        a = array.array(self.typecode, self.example)
574        a[-1000:] = a
575        self.assertEqual(
576            a,
577            array.array(self.typecode, self.example)
578        )
579
580        a = array.array(self.typecode, self.example)
581        a[:1000] = a
582        self.assertEqual(
583            a,
584            array.array(self.typecode, self.example)
585        )
586
587        a = array.array(self.typecode, self.example)
588        a[:-1000] = a
589        self.assertEqual(
590            a,
591            array.array(self.typecode, 2*self.example)
592        )
593
594        a = array.array(self.typecode, self.example)
595        a[1:0] = a
596        self.assertEqual(
597            a,
598            array.array(self.typecode, self.example[:1] + self.example + self.example[1:])
599        )
600
601        a = array.array(self.typecode, self.example)
602        a[2000:1000] = a
603        self.assertEqual(
604            a,
605            array.array(self.typecode, 2*self.example)
606        )
607
608        a = array.array(self.typecode, self.example)
609        self.assertRaises(TypeError, a.__setslice__, 0, 0, None)
610        self.assertRaises(TypeError, a.__setitem__, slice(0, 0), None)
611        self.assertRaises(TypeError, a.__setitem__, slice(0, 1), None)
612
613        b = array.array(self.badtypecode())
614        self.assertRaises(TypeError, a.__setslice__, 0, 0, b)
615        self.assertRaises(TypeError, a.__setitem__, slice(0, 0), b)
616        self.assertRaises(TypeError, a.__setitem__, slice(0, 1), b)
617
618    def test_extended_set_del_slice(self):
619        indices = (0, None, 1, 3, 19, 100, -1, -2, -31, -100)
620        for start in indices:
621            for stop in indices:
622                # Everything except the initial 0 (invalid step)
623                for step in indices[1:]:
624                    a = array.array(self.typecode, self.example)
625                    L = list(a)
626                    # Make sure we have a slice of exactly the right length,
627                    # but with (hopefully) different data.
628                    data = L[start:stop:step]
629                    data.reverse()
630                    L[start:stop:step] = data
631                    a[start:stop:step] = array.array(self.typecode, data)
632                    self.assertEqual(a, array.array(self.typecode, L))
633
634                    del L[start:stop:step]
635                    del a[start:stop:step]
636                    self.assertEqual(a, array.array(self.typecode, L))
637
638    def test_index(self):
639        example = 2*self.example
640        a = array.array(self.typecode, example)
641        self.assertRaises(TypeError, a.index)
642        for x in example:
643            self.assertEqual(a.index(x), example.index(x))
644        self.assertRaises(ValueError, a.index, None)
645        self.assertRaises(ValueError, a.index, self.outside)
646
647    def test_count(self):
648        example = 2*self.example
649        a = array.array(self.typecode, example)
650        self.assertRaises(TypeError, a.count)
651        for x in example:
652            self.assertEqual(a.count(x), example.count(x))
653        self.assertEqual(a.count(self.outside), 0)
654        self.assertEqual(a.count(None), 0)
655
656    def test_remove(self):
657        for x in self.example:
658            example = 2*self.example
659            a = array.array(self.typecode, example)
660            pos = example.index(x)
661            example2 = example[:pos] + example[pos+1:]
662            a.remove(x)
663            self.assertEqual(a, array.array(self.typecode, example2))
664
665        a = array.array(self.typecode, self.example)
666        self.assertRaises(ValueError, a.remove, self.outside)
667
668        self.assertRaises(ValueError, a.remove, None)
669
670    def test_pop(self):
671        a = array.array(self.typecode)
672        self.assertRaises(IndexError, a.pop)
673
674        a = array.array(self.typecode, 2*self.example)
675        self.assertRaises(TypeError, a.pop, 42, 42)
676        self.assertRaises(TypeError, a.pop, None)
677        self.assertRaises(IndexError, a.pop, len(a))
678        self.assertRaises(IndexError, a.pop, -len(a)-1)
679
680        self.assertEntryEqual(a.pop(0), self.example[0])
681        self.assertEqual(
682            a,
683            array.array(self.typecode, self.example[1:]+self.example)
684        )
685        self.assertEntryEqual(a.pop(1), self.example[2])
686        self.assertEqual(
687            a,
688            array.array(self.typecode, self.example[1:2]+self.example[3:]+self.example)
689        )
690        self.assertEntryEqual(a.pop(0), self.example[1])
691        self.assertEntryEqual(a.pop(), self.example[-1])
692        self.assertEqual(
693            a,
694            array.array(self.typecode, self.example[3:]+self.example[:-1])
695        )
696
697    def test_reverse(self):
698        a = array.array(self.typecode, self.example)
699        self.assertRaises(TypeError, a.reverse, 42)
700        a.reverse()
701        self.assertEqual(
702            a,
703            array.array(self.typecode, self.example[::-1])
704        )
705
706    def test_extend(self):
707        a = array.array(self.typecode, self.example)
708        self.assertRaises(TypeError, a.extend)
709        a.extend(array.array(self.typecode, self.example[::-1]))
710        self.assertEqual(
711            a,
712            array.array(self.typecode, self.example+self.example[::-1])
713        )
714
715        a = array.array(self.typecode, self.example)
716        a.extend(a)
717        self.assertEqual(
718            a,
719            array.array(self.typecode, self.example+self.example)
720        )
721
722        b = array.array(self.badtypecode())
723        self.assertRaises(TypeError, a.extend, b)
724
725        a = array.array(self.typecode, self.example)
726        a.extend(self.example[::-1])
727        self.assertEqual(
728            a,
729            array.array(self.typecode, self.example+self.example[::-1])
730        )
731
732    def test_constructor_with_iterable_argument(self):
733        a = array.array(self.typecode, iter(self.example))
734        b = array.array(self.typecode, self.example)
735        self.assertEqual(a, b)
736
737        # non-iterable argument
738        self.assertRaises(TypeError, array.array, self.typecode, 10)
739
740        # pass through errors raised in __iter__
741        class A:
742            def __iter__(self):
743                raise UnicodeError
744        self.assertRaises(UnicodeError, array.array, self.typecode, A())
745
746        # pass through errors raised in next()
747        def B():
748            raise UnicodeError
749            yield None
750        self.assertRaises(UnicodeError, array.array, self.typecode, B())
751
752    def test_coveritertraverse(self):
753        try:
754            import gc
755        except ImportError:
756            return
757        a = array.array(self.typecode)
758        l = [iter(a)]
759        l.append(l)
760        gc.collect()
761
762    def test_buffer(self):
763        a = array.array(self.typecode, self.example)
764        with test_support.check_py3k_warnings():
765            b = buffer(a)
766        self.assertEqual(b[0], a.tostring()[0])
767
768    def test_weakref(self):
769        s = array.array(self.typecode, self.example)
770        p = proxy(s)
771        self.assertEqual(p.tostring(), s.tostring())
772        s = None
773        self.assertRaises(ReferenceError, len, p)
774
775    def test_bug_782369(self):
776        import sys
777        if hasattr(sys, "getrefcount"):
778            for i in range(10):
779                b = array.array('B', range(64))
780            rc = sys.getrefcount(10)
781            for i in range(10):
782                b = array.array('B', range(64))
783            self.assertEqual(rc, sys.getrefcount(10))
784
785    def test_subclass_with_kwargs(self):
786        # SF bug #1486663 -- this used to erroneously raise a TypeError
787        with warnings.catch_warnings():
788            warnings.filterwarnings("ignore", '', DeprecationWarning)
789            ArraySubclassWithKwargs('b', newarg=1)
790
791
792class StringTest(BaseTest):
793
794    def test_setitem(self):
795        super(StringTest, self).test_setitem()
796        a = array.array(self.typecode, self.example)
797        self.assertRaises(TypeError, a.__setitem__, 0, self.example[:2])
798
799class CharacterTest(StringTest):
800    typecode = 'c'
801    example = '\x01azAZ\x00\xfe'
802    smallerexample = '\x01azAY\x00\xfe'
803    biggerexample = '\x01azAZ\x00\xff'
804    outside = '\x33'
805    minitemsize = 1
806
807    def test_subbclassing(self):
808        class EditableString(array.array):
809            def __new__(cls, s, *args, **kwargs):
810                return array.array.__new__(cls, 'c', s)
811
812            def __init__(self, s, color='blue'):
813                self.color = color
814
815            def strip(self):
816                self[:] = array.array('c', self.tostring().strip())
817
818            def __repr__(self):
819                return 'EditableString(%r)' % self.tostring()
820
821        s = EditableString("\ttest\r\n")
822        s.strip()
823        self.assertEqual(s.tostring(), "test")
824
825        self.assertEqual(s.color, "blue")
826        s.color = "red"
827        self.assertEqual(s.color, "red")
828        self.assertEqual(s.__dict__.keys(), ["color"])
829
830    def test_nounicode(self):
831        a = array.array(self.typecode, self.example)
832        self.assertRaises(ValueError, a.fromunicode, unicode(''))
833        self.assertRaises(ValueError, a.tounicode)
834
835tests.append(CharacterTest)
836
837if test_support.have_unicode:
838    class UnicodeTest(StringTest):
839        typecode = 'u'
840        example = unicode(r'\x01\u263a\x00\ufeff', 'unicode-escape')
841        smallerexample = unicode(r'\x01\u263a\x00\ufefe', 'unicode-escape')
842        biggerexample = unicode(r'\x01\u263a\x01\ufeff', 'unicode-escape')
843        outside = unicode('\x33')
844        minitemsize = 2
845
846        def test_unicode(self):
847            self.assertRaises(TypeError, array.array, 'b', unicode('foo', 'ascii'))
848
849            a = array.array('u', unicode(r'\xa0\xc2\u1234', 'unicode-escape'))
850            a.fromunicode(unicode(' ', 'ascii'))
851            a.fromunicode(unicode('', 'ascii'))
852            a.fromunicode(unicode('', 'ascii'))
853            a.fromunicode(unicode(r'\x11abc\xff\u1234', 'unicode-escape'))
854            s = a.tounicode()
855            self.assertEqual(
856                s,
857                unicode(r'\xa0\xc2\u1234 \x11abc\xff\u1234', 'unicode-escape')
858            )
859
860            s = unicode(r'\x00="\'a\\b\x80\xff\u0000\u0001\u1234', 'unicode-escape')
861            a = array.array('u', s)
862            self.assertEqual(
863                repr(a),
864                r"""array('u', u'\x00="\'a\\b\x80\xff\x00\x01\u1234')"""
865            )
866
867            self.assertRaises(TypeError, a.fromunicode)
868
869    tests.append(UnicodeTest)
870
871class NumberTest(BaseTest):
872
873    def test_extslice(self):
874        a = array.array(self.typecode, range(5))
875        self.assertEqual(a[::], a)
876        self.assertEqual(a[::2], array.array(self.typecode, [0,2,4]))
877        self.assertEqual(a[1::2], array.array(self.typecode, [1,3]))
878        self.assertEqual(a[::-1], array.array(self.typecode, [4,3,2,1,0]))
879        self.assertEqual(a[::-2], array.array(self.typecode, [4,2,0]))
880        self.assertEqual(a[3::-2], array.array(self.typecode, [3,1]))
881        self.assertEqual(a[-100:100:], a)
882        self.assertEqual(a[100:-100:-1], a[::-1])
883        self.assertEqual(a[-100L:100L:2L], array.array(self.typecode, [0,2,4]))
884        self.assertEqual(a[1000:2000:2], array.array(self.typecode, []))
885        self.assertEqual(a[-1000:-2000:-2], array.array(self.typecode, []))
886
887    def test_delslice(self):
888        a = array.array(self.typecode, range(5))
889        del a[::2]
890        self.assertEqual(a, array.array(self.typecode, [1,3]))
891        a = array.array(self.typecode, range(5))
892        del a[1::2]
893        self.assertEqual(a, array.array(self.typecode, [0,2,4]))
894        a = array.array(self.typecode, range(5))
895        del a[1::-2]
896        self.assertEqual(a, array.array(self.typecode, [0,2,3,4]))
897        a = array.array(self.typecode, range(10))
898        del a[::1000]
899        self.assertEqual(a, array.array(self.typecode, [1,2,3,4,5,6,7,8,9]))
900        # test issue7788
901        a = array.array(self.typecode, range(10))
902        del a[9::1<<333]
903
904    def test_assignment(self):
905        a = array.array(self.typecode, range(10))
906        a[::2] = array.array(self.typecode, [42]*5)
907        self.assertEqual(a, array.array(self.typecode, [42, 1, 42, 3, 42, 5, 42, 7, 42, 9]))
908        a = array.array(self.typecode, range(10))
909        a[::-4] = array.array(self.typecode, [10]*3)
910        self.assertEqual(a, array.array(self.typecode, [0, 10, 2, 3, 4, 10, 6, 7, 8 ,10]))
911        a = array.array(self.typecode, range(4))
912        a[::-1] = a
913        self.assertEqual(a, array.array(self.typecode, [3, 2, 1, 0]))
914        a = array.array(self.typecode, range(10))
915        b = a[:]
916        c = a[:]
917        ins = array.array(self.typecode, range(2))
918        a[2:3] = ins
919        b[slice(2,3)] = ins
920        c[2:3:] = ins
921
922    def test_iterationcontains(self):
923        a = array.array(self.typecode, range(10))
924        self.assertEqual(list(a), range(10))
925        b = array.array(self.typecode, [20])
926        self.assertEqual(a[-1] in a, True)
927        self.assertEqual(b[0] not in a, True)
928
929    def check_overflow(self, lower, upper):
930        # method to be used by subclasses
931
932        # should not overflow assigning lower limit
933        a = array.array(self.typecode, [lower])
934        a[0] = lower
935        # should overflow assigning less than lower limit
936        self.assertRaises(OverflowError, array.array, self.typecode, [lower-1])
937        self.assertRaises(OverflowError, a.__setitem__, 0, lower-1)
938        # should not overflow assigning upper limit
939        a = array.array(self.typecode, [upper])
940        a[0] = upper
941        # should overflow assigning more than upper limit
942        self.assertRaises(OverflowError, array.array, self.typecode, [upper+1])
943        self.assertRaises(OverflowError, a.__setitem__, 0, upper+1)
944
945    def test_subclassing(self):
946        typecode = self.typecode
947        class ExaggeratingArray(array.array):
948            __slots__ = ['offset']
949
950            def __new__(cls, typecode, data, offset):
951                return array.array.__new__(cls, typecode, data)
952
953            def __init__(self, typecode, data, offset):
954                self.offset = offset
955
956            def __getitem__(self, i):
957                return array.array.__getitem__(self, i) + self.offset
958
959        a = ExaggeratingArray(self.typecode, [3, 6, 7, 11], 4)
960        self.assertEntryEqual(a[0], 7)
961
962        self.assertRaises(AttributeError, setattr, a, "color", "blue")
963
964class SignedNumberTest(NumberTest):
965    example = [-1, 0, 1, 42, 0x7f]
966    smallerexample = [-1, 0, 1, 42, 0x7e]
967    biggerexample = [-1, 0, 1, 43, 0x7f]
968    outside = 23
969
970    def test_overflow(self):
971        a = array.array(self.typecode)
972        lower = -1 * long(pow(2, a.itemsize * 8 - 1))
973        upper = long(pow(2, a.itemsize * 8 - 1)) - 1L
974        self.check_overflow(lower, upper)
975
976class UnsignedNumberTest(NumberTest):
977    example = [0, 1, 17, 23, 42, 0xff]
978    smallerexample = [0, 1, 17, 23, 42, 0xfe]
979    biggerexample = [0, 1, 17, 23, 43, 0xff]
980    outside = 0xaa
981
982    def test_overflow(self):
983        a = array.array(self.typecode)
984        lower = 0
985        upper = long(pow(2, a.itemsize * 8)) - 1L
986        self.check_overflow(lower, upper)
987
988    @test_support.cpython_only
989    def test_sizeof_with_buffer(self):
990        a = array.array(self.typecode, self.example)
991        basesize = test_support.calcvobjsize('4P')
992        buffer_size = a.buffer_info()[1] * a.itemsize
993        test_support.check_sizeof(self, a, basesize + buffer_size)
994
995    @test_support.cpython_only
996    def test_sizeof_without_buffer(self):
997        a = array.array(self.typecode)
998        basesize = test_support.calcvobjsize('4P')
999        test_support.check_sizeof(self, a, basesize)
1000
1001
1002class ByteTest(SignedNumberTest):
1003    typecode = 'b'
1004    minitemsize = 1
1005tests.append(ByteTest)
1006
1007class UnsignedByteTest(UnsignedNumberTest):
1008    typecode = 'B'
1009    minitemsize = 1
1010tests.append(UnsignedByteTest)
1011
1012class ShortTest(SignedNumberTest):
1013    typecode = 'h'
1014    minitemsize = 2
1015tests.append(ShortTest)
1016
1017class UnsignedShortTest(UnsignedNumberTest):
1018    typecode = 'H'
1019    minitemsize = 2
1020tests.append(UnsignedShortTest)
1021
1022class IntTest(SignedNumberTest):
1023    typecode = 'i'
1024    minitemsize = 2
1025tests.append(IntTest)
1026
1027class UnsignedIntTest(UnsignedNumberTest):
1028    typecode = 'I'
1029    minitemsize = 2
1030tests.append(UnsignedIntTest)
1031
1032class LongTest(SignedNumberTest):
1033    typecode = 'l'
1034    minitemsize = 4
1035tests.append(LongTest)
1036
1037class UnsignedLongTest(UnsignedNumberTest):
1038    typecode = 'L'
1039    minitemsize = 4
1040tests.append(UnsignedLongTest)
1041
1042class FPTest(NumberTest):
1043    example = [-42.0, 0, 42, 1e5, -1e10]
1044    smallerexample = [-42.0, 0, 42, 1e5, -2e10]
1045    biggerexample = [-42.0, 0, 42, 1e5, 1e10]
1046    outside = 23
1047
1048    def assertEntryEqual(self, entry1, entry2):
1049        self.assertAlmostEqual(entry1, entry2)
1050
1051    def test_byteswap(self):
1052        a = array.array(self.typecode, self.example)
1053        self.assertRaises(TypeError, a.byteswap, 42)
1054        if a.itemsize in (1, 2, 4, 8):
1055            b = array.array(self.typecode, self.example)
1056            b.byteswap()
1057            if a.itemsize==1:
1058                self.assertEqual(a, b)
1059            else:
1060                # On alphas treating the byte swapped bit patters as
1061                # floats/doubles results in floating point exceptions
1062                # => compare the 8bit string values instead
1063                self.assertNotEqual(a.tostring(), b.tostring())
1064            b.byteswap()
1065            self.assertEqual(a, b)
1066
1067class FloatTest(FPTest):
1068    typecode = 'f'
1069    minitemsize = 4
1070tests.append(FloatTest)
1071
1072class DoubleTest(FPTest):
1073    typecode = 'd'
1074    minitemsize = 8
1075
1076    def test_alloc_overflow(self):
1077        from sys import maxsize
1078        a = array.array('d', [-1]*65536)
1079        try:
1080            a *= maxsize//65536 + 1
1081        except MemoryError:
1082            pass
1083        else:
1084            self.fail("Array of size > maxsize created - MemoryError expected")
1085        b = array.array('d', [ 2.71828183, 3.14159265, -1])
1086        try:
1087            b * (maxsize//3 + 1)
1088        except MemoryError:
1089            pass
1090        else:
1091            self.fail("Array of size > maxsize created - MemoryError expected")
1092
1093tests.append(DoubleTest)
1094
1095def test_main(verbose=None):
1096    import sys
1097
1098    test_support.run_unittest(*tests)
1099
1100    # verify reference counting
1101    if verbose and hasattr(sys, "gettotalrefcount"):
1102        import gc
1103        counts = [None] * 5
1104        for i in xrange(len(counts)):
1105            test_support.run_unittest(*tests)
1106            gc.collect()
1107            counts[i] = sys.gettotalrefcount()
1108        print counts
1109
1110if __name__ == "__main__":
1111    test_main(verbose=True)
1112