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