1
# Copyright (C) 2009, 2010, 2011 Canonical Ltd
1
# Copyright (C) 2009, 2010 Canonical Ltd
3
3
# This program is free software; you can redistribute it and/or modify
4
4
# it under the terms of the GNU General Public License as published by
17
17
"""Tests for the StaticTuple type."""
20
import cPickle as pickle
33
from breezy.sixish import (
37
from breezy.tests import (
42
def load_tests(loader, standard_tests, pattern):
33
def load_tests(standard_tests, module, loader):
43
34
"""Parameterize tests for all versions of groupcompress."""
44
35
global compiled_static_tuple_feature
45
36
suite, compiled_static_tuple_feature = tests.permute_tests_for_extension(
46
standard_tests, loader, 'breezy._static_tuple_py',
47
'breezy._static_tuple_c')
37
standard_tests, loader, 'bzrlib._static_tuple_py',
38
'bzrlib._static_tuple_c')
42
class _Meliae(tests.Feature):
46
from meliae import scanner
51
def feature_name(self):
52
return "Meliae - python memory debugger"
51
57
class TestStaticTuple(tests.TestCase):
53
59
def assertRefcount(self, count, obj):
62
68
# self.assertEqual(count, sys.getrefcount(obj)-1)
63
69
# Then it works fine. Something about passing it to assertRefcount is
64
70
# actually double-incrementing (and decrementing) the refcount
65
self.assertEqual(count, sys.getrefcount(obj) - 3)
71
self.assertEqual(count, sys.getrefcount(obj)-3)
67
73
def test_create(self):
68
74
k = self.module.StaticTuple('foo')
69
75
k = self.module.StaticTuple('foo', 'bar')
71
77
def test_create_bad_args(self):
72
args_256 = ['a'] * 256
74
80
self.assertRaises(TypeError, self.module.StaticTuple, *args_256)
75
args_300 = ['a'] * 300
76
82
self.assertRaises(TypeError, self.module.StaticTuple, *args_300)
78
84
self.assertRaises(TypeError, self.module.StaticTuple, object())
112
118
def test_concat_with_non_tuple(self):
113
119
st1 = self.module.StaticTuple('foo')
114
120
self.assertRaises(TypeError, lambda: st1 + 10)
116
122
def test_as_tuple(self):
117
123
k = self.module.StaticTuple('foo')
155
161
self.assertEqual(2, len(k))
156
162
k = self.module.StaticTuple('foo', 'bar', 'b', 'b', 'b', 'b', 'b')
157
163
self.assertEqual(7, len(k))
159
165
k = self.module.StaticTuple(*args)
160
166
self.assertEqual(255, len(k))
174
180
self.assertEqual('z', k[6])
175
181
self.assertEqual('z', k[-1])
176
182
self.assertRaises(IndexError, k.__getitem__, 7)
177
self.assertRaises(IndexError, k.__getitem__, 256 + 7)
183
self.assertRaises(IndexError, k.__getitem__, 256+7)
178
184
self.assertRaises(IndexError, k.__getitem__, 12024)
179
185
# Python's [] resolver handles the negative arguments, so we can't
180
186
# really test StaticTuple_item() with negative values.
184
190
def test_refcount(self):
186
num_refs = sys.getrefcount(f) - 1 # sys.getrefcount() adds one
192
num_refs = sys.getrefcount(f) - 1 #sys.getrefcount() adds one
187
193
k = self.module.StaticTuple(f)
188
194
self.assertRefcount(num_refs + 1, f)
216
222
def test_holds_int(self):
217
223
k1 = self.module.StaticTuple(1)
219
224
class subint(int):
221
226
# But not a subclass, because subint could introduce refcycles
222
227
self.assertRaises(TypeError, self.module.StaticTuple, subint(2))
224
229
def test_holds_long(self):
226
self.skipTest("No long type on Python 3")
227
k1 = self.module.StaticTuple(2**65)
230
k1 = self.module.StaticTuple(2L**65)
229
231
class sublong(long):
231
233
# But not a subclass
234
236
def test_holds_float(self):
235
237
k1 = self.module.StaticTuple(1.2)
237
238
class subfloat(float):
239
240
self.assertRaises(TypeError, self.module.StaticTuple, subfloat(1.5))
241
def test_holds_bytes(self):
242
k1 = self.module.StaticTuple(b'astring')
242
def test_holds_str(self):
243
k1 = self.module.StaticTuple('astring')
246
self.assertRaises(TypeError, self.module.StaticTuple, substr(b'a'))
246
self.assertRaises(TypeError, self.module.StaticTuple, substr('a'))
248
248
def test_holds_unicode(self):
249
249
k1 = self.module.StaticTuple(u'\xb5')
251
class subunicode(text_type):
250
class subunicode(unicode):
253
252
self.assertRaises(TypeError, self.module.StaticTuple,
254
253
subunicode(u'\xb5'))
293
292
k6 = self.module.StaticTuple(k3, k4)
294
293
self.assertCompareEqual(k5, k6)
296
def check_strict_compare(self, k1, k2, mismatched_types):
297
"""True if on Python 3 and stricter comparison semantics are used."""
298
if PY3 and mismatched_types:
299
for op in ("ge", "gt", "le", "lt"):
300
self.assertRaises(TypeError, getattr(operator, op), k1, k2)
304
def assertCompareDifferent(self, k_small, k_big, mismatched_types=False):
295
def assertCompareDifferent(self, k_small, k_big):
305
296
self.assertFalse(k_small == k_big)
297
self.assertFalse(k_small >= k_big)
298
self.assertFalse(k_small > k_big)
306
299
self.assertTrue(k_small != k_big)
307
if not self.check_strict_compare(k_small, k_big, mismatched_types):
308
self.assertFalse(k_small >= k_big)
309
self.assertFalse(k_small > k_big)
310
self.assertTrue(k_small <= k_big)
311
self.assertTrue(k_small < k_big)
300
self.assertTrue(k_small <= k_big)
301
self.assertTrue(k_small < k_big)
313
def assertCompareNoRelation(self, k1, k2, mismatched_types=False):
303
def assertCompareNoRelation(self, k1, k2):
314
304
"""Run the comparison operators, make sure they do something.
316
306
However, we don't actually care what comes first or second. This is
320
310
self.assertFalse(k1 == k2)
321
311
self.assertTrue(k1 != k2)
322
if not self.check_strict_compare(k1, k2, mismatched_types):
323
# Do the comparison, but we don't care about the result
312
# Do the comparison, but we don't care about the result
329
318
def test_compare_vs_none(self):
330
319
k1 = self.module.StaticTuple('baz', 'bing')
331
self.assertCompareDifferent(None, k1, mismatched_types=True)
320
self.assertCompareDifferent(None, k1)
333
322
def test_compare_cross_class(self):
334
323
k1 = self.module.StaticTuple('baz', 'bing')
335
self.assertCompareNoRelation(10, k1, mismatched_types=True)
336
self.assertCompareNoRelation('baz', k1, mismatched_types=True)
324
self.assertCompareNoRelation(10, k1)
325
self.assertCompareNoRelation('baz', k1)
338
327
def test_compare_all_different_same_width(self):
339
328
k1 = self.module.StaticTuple('baz', 'bing')
360
349
k4 = self.module.StaticTuple(k1, k2)
361
350
self.assertCompareDifferent(k3, k4)
362
351
k5 = self.module.StaticTuple('foo', None)
363
self.assertCompareDifferent(k5, k1, mismatched_types=True)
364
self.assertCompareDifferent(k5, k2, mismatched_types=True)
352
self.assertCompareDifferent(k5, k1)
353
self.assertCompareDifferent(k5, k2)
366
355
def test_compare_diff_width(self):
367
356
k1 = self.module.StaticTuple('foo')
375
364
k1 = self.module.StaticTuple('foo', 'bar')
376
365
k2 = self.module.StaticTuple('foo', 1, None, u'\xb5', 1.2, 2**65, True,
378
self.assertCompareNoRelation(k1, k2, mismatched_types=True)
367
self.assertCompareNoRelation(k1, k2)
379
368
k3 = self.module.StaticTuple('foo')
380
369
self.assertCompareDifferent(k3, k1)
381
370
k4 = self.module.StaticTuple(None)
382
self.assertCompareDifferent(k4, k1, mismatched_types=True)
371
self.assertCompareDifferent(k4, k1)
383
372
k5 = self.module.StaticTuple(1)
384
self.assertCompareNoRelation(k1, k5, mismatched_types=True)
373
self.assertCompareNoRelation(k1, k5)
386
375
def test_compare_to_tuples(self):
387
376
k1 = self.module.StaticTuple('foo')
397
386
self.assertCompareDifferent(('foo',), k2)
398
387
self.assertCompareDifferent(('foo', 'aaa'), k2)
399
388
self.assertCompareDifferent(('baz', 'bing'), k2)
400
self.assertCompareDifferent(('foo', 10), k2, mismatched_types=True)
389
self.assertCompareDifferent(('foo', 10), k2)
402
391
k3 = self.module.StaticTuple(k1, k2)
403
392
self.assertCompareEqual(k3, (('foo',), ('foo', 'bar')))
413
402
# This requires comparing a StaticTuple to a 'string', and then
414
403
# interpreting that value in the next higher StaticTuple. This used to
415
404
# generate a PyErr_BadIternalCall. We now fall back to *something*.
416
self.assertCompareNoRelation(k1, k2, mismatched_types=True)
405
self.assertCompareNoRelation(k1, k2)
418
407
def test_hash(self):
419
408
k = self.module.StaticTuple('foo')
441
430
k = self.module.StaticTuple('foo', 'bar', 'baz', 'bing')
442
431
self.assertEqual(('foo', 'bar'), k[:2])
443
432
self.assertEqual(('baz',), k[2:-1])
444
self.assertEqual(('foo', 'baz',), k[::2])
445
self.assertRaises(TypeError, k.__getitem__, 'not_slice')
436
# C implementation raises a TypeError, we don't need the
437
# implementation yet, so allow this to pass
440
# Python implementation uses a regular Tuple, so make sure it gives
442
self.assertEqual(('foo', 'baz'), val)
447
444
def test_referents(self):
448
445
# We implement tp_traverse so that things like 'meliae' can measure the
449
446
# amount of referenced memory. Unfortunately gc.get_referents() first
450
447
# checks the IS_GC flag before it traverses anything. We could write a
451
448
# helper func, but that won't work for the generic implementation...
452
self.requireFeature(features.meliae)
449
self.requireFeature(Meliae)
453
450
from meliae import scanner
454
451
strs = ['foo', 'bar', 'baz', 'bing']
455
452
k = self.module.StaticTuple(*strs)
460
457
self.assertEqual(sorted(refs), sorted(scanner.get_referents(k)))
462
459
def test_nested_referents(self):
463
self.requireFeature(features.meliae)
460
self.requireFeature(Meliae)
464
461
from meliae import scanner
465
462
strs = ['foo', 'bar', 'baz', 'bing']
466
463
k1 = self.module.StaticTuple(*strs[:2])
494
491
def test__c_intern_handles_refcount(self):
495
492
if self.module is _static_tuple_py:
496
return # Not applicable
493
return # Not applicable
497
494
unique_str1 = 'unique str ' + osutils.rand_chars(20)
498
495
unique_str2 = 'unique str ' + osutils.rand_chars(20)
499
496
key = self.module.StaticTuple(unique_str1, unique_str2)
529
526
def test__c_keys_are_not_immortal(self):
530
527
if self.module is _static_tuple_py:
531
return # Not applicable
528
return # Not applicable
532
529
unique_str1 = 'unique str ' + osutils.rand_chars(20)
533
530
unique_str2 = 'unique str ' + osutils.rand_chars(20)
534
531
key = self.module.StaticTuple(unique_str1, unique_str2)
600
597
def test_pickle(self):
601
598
st = self.module.StaticTuple('foo', 'bar')
602
pickled = pickle.dumps(st)
603
unpickled = pickle.loads(pickled)
599
pickled = cPickle.dumps(st)
600
unpickled = cPickle.loads(pickled)
604
601
self.assertEqual(unpickled, st)
606
603
def test_pickle_empty(self):
607
604
st = self.module.StaticTuple()
608
pickled = pickle.dumps(st)
609
unpickled = pickle.loads(pickled)
605
pickled = cPickle.dumps(st)
606
unpickled = cPickle.loads(pickled)
610
607
self.assertIs(st, unpickled)
612
609
def test_pickle_nested(self):
613
610
st = self.module.StaticTuple('foo', self.module.StaticTuple('bar'))
614
pickled = pickle.dumps(st)
615
unpickled = pickle.loads(pickled)
611
pickled = cPickle.dumps(st)
612
unpickled = cPickle.loads(pickled)
616
613
self.assertEqual(unpickled, st)
618
615
def test_static_tuple_thunk(self):
619
616
# Make sure the right implementation is available from
620
# breezy.static_tuple.StaticTuple.
617
# bzrlib.static_tuple.StaticTuple.
621
618
if self.module is _static_tuple_py:
622
619
if compiled_static_tuple_feature.available():
623
620
# We will be using the C version