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.tests import (
38
def load_tests(loader, standard_tests, pattern):
34
39
"""Parameterize tests for all versions of groupcompress."""
35
40
global compiled_static_tuple_feature
36
41
suite, compiled_static_tuple_feature = tests.permute_tests_for_extension(
37
standard_tests, loader, 'bzrlib._static_tuple_py',
38
'bzrlib._static_tuple_c')
42
standard_tests, loader, 'breezy._static_tuple_py',
43
'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
47
class TestStaticTuple(tests.TestCase):
59
49
def assertRefcount(self, count, obj):
68
58
# self.assertEqual(count, sys.getrefcount(obj)-1)
69
59
# Then it works fine. Something about passing it to assertRefcount is
70
60
# actually double-incrementing (and decrementing) the refcount
71
self.assertEqual(count, sys.getrefcount(obj)-3)
61
self.assertEqual(count, sys.getrefcount(obj) - 3)
73
63
def test_create(self):
74
64
k = self.module.StaticTuple('foo')
75
65
k = self.module.StaticTuple('foo', 'bar')
77
67
def test_create_bad_args(self):
68
args_256 = ['a'] * 256
80
70
self.assertRaises(TypeError, self.module.StaticTuple, *args_256)
71
args_300 = ['a'] * 300
82
72
self.assertRaises(TypeError, self.module.StaticTuple, *args_300)
84
74
self.assertRaises(TypeError, self.module.StaticTuple, object())
118
108
def test_concat_with_non_tuple(self):
119
109
st1 = self.module.StaticTuple('foo')
120
110
self.assertRaises(TypeError, lambda: st1 + 10)
122
112
def test_as_tuple(self):
123
113
k = self.module.StaticTuple('foo')
161
151
self.assertEqual(2, len(k))
162
152
k = self.module.StaticTuple('foo', 'bar', 'b', 'b', 'b', 'b', 'b')
163
153
self.assertEqual(7, len(k))
165
155
k = self.module.StaticTuple(*args)
166
156
self.assertEqual(255, len(k))
180
170
self.assertEqual('z', k[6])
181
171
self.assertEqual('z', k[-1])
182
172
self.assertRaises(IndexError, k.__getitem__, 7)
183
self.assertRaises(IndexError, k.__getitem__, 256+7)
173
self.assertRaises(IndexError, k.__getitem__, 256 + 7)
184
174
self.assertRaises(IndexError, k.__getitem__, 12024)
185
175
# Python's [] resolver handles the negative arguments, so we can't
186
176
# really test StaticTuple_item() with negative values.
190
180
def test_refcount(self):
192
num_refs = sys.getrefcount(f) - 1 #sys.getrefcount() adds one
182
num_refs = sys.getrefcount(f) - 1 # sys.getrefcount() adds one
193
183
k = self.module.StaticTuple(f)
194
184
self.assertRefcount(num_refs + 1, f)
222
212
def test_holds_int(self):
223
213
k1 = self.module.StaticTuple(1)
224
215
class subint(int):
226
217
# But not a subclass, because subint could introduce refcycles
227
218
self.assertRaises(TypeError, self.module.StaticTuple, subint(2))
229
def test_holds_long(self):
230
k1 = self.module.StaticTuple(2L**65)
234
self.assertRaises(TypeError, self.module.StaticTuple, sublong(1))
236
220
def test_holds_float(self):
237
221
k1 = self.module.StaticTuple(1.2)
238
223
class subfloat(float):
240
225
self.assertRaises(TypeError, self.module.StaticTuple, subfloat(1.5))
242
def test_holds_str(self):
243
k1 = self.module.StaticTuple('astring')
227
def test_holds_bytes(self):
228
k1 = self.module.StaticTuple(b'astring')
246
self.assertRaises(TypeError, self.module.StaticTuple, substr('a'))
232
self.assertRaises(TypeError, self.module.StaticTuple, substr(b'a'))
248
234
def test_holds_unicode(self):
249
235
k1 = self.module.StaticTuple(u'\xb5')
250
class subunicode(unicode):
237
class subunicode(str):
252
239
self.assertRaises(TypeError, self.module.StaticTuple,
253
240
subunicode(u'\xb5'))
292
279
k6 = self.module.StaticTuple(k3, k4)
293
280
self.assertCompareEqual(k5, k6)
295
def assertCompareDifferent(self, k_small, k_big):
282
def check_strict_compare(self, k1, k2, mismatched_types):
283
"""True if on Python 3 and stricter comparison semantics are used."""
285
for op in ("ge", "gt", "le", "lt"):
286
self.assertRaises(TypeError, getattr(operator, op), k1, k2)
290
def assertCompareDifferent(self, k_small, k_big, mismatched_types=False):
296
291
self.assertFalse(k_small == k_big)
297
self.assertFalse(k_small >= k_big)
298
self.assertFalse(k_small > k_big)
299
292
self.assertTrue(k_small != k_big)
300
self.assertTrue(k_small <= k_big)
301
self.assertTrue(k_small < k_big)
293
if not self.check_strict_compare(k_small, k_big, mismatched_types):
294
self.assertFalse(k_small >= k_big)
295
self.assertFalse(k_small > k_big)
296
self.assertTrue(k_small <= k_big)
297
self.assertTrue(k_small < k_big)
303
def assertCompareNoRelation(self, k1, k2):
299
def assertCompareNoRelation(self, k1, k2, mismatched_types=False):
304
300
"""Run the comparison operators, make sure they do something.
306
302
However, we don't actually care what comes first or second. This is
310
306
self.assertFalse(k1 == k2)
311
307
self.assertTrue(k1 != k2)
312
# Do the comparison, but we don't care about the result
308
if not self.check_strict_compare(k1, k2, mismatched_types):
309
# Do the comparison, but we don't care about the result
318
315
def test_compare_vs_none(self):
319
316
k1 = self.module.StaticTuple('baz', 'bing')
320
self.assertCompareDifferent(None, k1)
317
self.assertCompareDifferent(None, k1, mismatched_types=True)
322
319
def test_compare_cross_class(self):
323
320
k1 = self.module.StaticTuple('baz', 'bing')
324
self.assertCompareNoRelation(10, k1)
325
self.assertCompareNoRelation('baz', k1)
321
self.assertCompareNoRelation(10, k1, mismatched_types=True)
322
self.assertCompareNoRelation('baz', k1, mismatched_types=True)
327
324
def test_compare_all_different_same_width(self):
328
325
k1 = self.module.StaticTuple('baz', 'bing')
349
346
k4 = self.module.StaticTuple(k1, k2)
350
347
self.assertCompareDifferent(k3, k4)
351
348
k5 = self.module.StaticTuple('foo', None)
352
self.assertCompareDifferent(k5, k1)
353
self.assertCompareDifferent(k5, k2)
349
self.assertCompareDifferent(k5, k1, mismatched_types=True)
350
self.assertCompareDifferent(k5, k2, mismatched_types=True)
355
352
def test_compare_diff_width(self):
356
353
k1 = self.module.StaticTuple('foo')
364
361
k1 = self.module.StaticTuple('foo', 'bar')
365
362
k2 = self.module.StaticTuple('foo', 1, None, u'\xb5', 1.2, 2**65, True,
367
self.assertCompareNoRelation(k1, k2)
364
self.assertCompareNoRelation(k1, k2, mismatched_types=True)
368
365
k3 = self.module.StaticTuple('foo')
369
366
self.assertCompareDifferent(k3, k1)
370
367
k4 = self.module.StaticTuple(None)
371
self.assertCompareDifferent(k4, k1)
368
self.assertCompareDifferent(k4, k1, mismatched_types=True)
372
369
k5 = self.module.StaticTuple(1)
373
self.assertCompareNoRelation(k1, k5)
370
self.assertCompareNoRelation(k1, k5, mismatched_types=True)
375
372
def test_compare_to_tuples(self):
376
373
k1 = self.module.StaticTuple('foo')
386
383
self.assertCompareDifferent(('foo',), k2)
387
384
self.assertCompareDifferent(('foo', 'aaa'), k2)
388
385
self.assertCompareDifferent(('baz', 'bing'), k2)
389
self.assertCompareDifferent(('foo', 10), k2)
386
self.assertCompareDifferent(('foo', 10), k2, mismatched_types=True)
391
388
k3 = self.module.StaticTuple(k1, k2)
392
389
self.assertCompareEqual(k3, (('foo',), ('foo', 'bar')))
402
399
# This requires comparing a StaticTuple to a 'string', and then
403
400
# interpreting that value in the next higher StaticTuple. This used to
404
401
# generate a PyErr_BadIternalCall. We now fall back to *something*.
405
self.assertCompareNoRelation(k1, k2)
402
self.assertCompareNoRelation(k1, k2, mismatched_types=True)
407
404
def test_hash(self):
408
405
k = self.module.StaticTuple('foo')
430
427
k = self.module.StaticTuple('foo', 'bar', 'baz', 'bing')
431
428
self.assertEqual(('foo', 'bar'), k[:2])
432
429
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)
430
self.assertEqual(('foo', 'baz',), k[::2])
431
self.assertRaises(TypeError, k.__getitem__, 'not_slice')
444
433
def test_referents(self):
445
434
# We implement tp_traverse so that things like 'meliae' can measure the
446
435
# amount of referenced memory. Unfortunately gc.get_referents() first
447
436
# checks the IS_GC flag before it traverses anything. We could write a
448
437
# helper func, but that won't work for the generic implementation...
449
self.requireFeature(Meliae)
438
self.requireFeature(features.meliae)
450
439
from meliae import scanner
451
440
strs = ['foo', 'bar', 'baz', 'bing']
452
441
k = self.module.StaticTuple(*strs)
454
443
refs = strs + [self.module.StaticTuple]
457
self.assertEqual(sorted(refs), sorted(scanner.get_referents(k)))
447
if isinstance(k, type):
449
if isinstance(k, str):
453
sorted(refs, key=key),
454
sorted(scanner.get_referents(k), key=key))
459
456
def test_nested_referents(self):
460
self.requireFeature(Meliae)
457
self.requireFeature(features.meliae)
461
458
from meliae import scanner
462
459
strs = ['foo', 'bar', 'baz', 'bing']
463
460
k1 = self.module.StaticTuple(*strs[:2])
467
464
if self.module is _static_tuple_py:
468
465
refs.append(self.module.StaticTuple)
469
self.assertEqual(sorted(refs),
470
sorted(scanner.get_referents(k3)))
467
if isinstance(k, type):
469
if isinstance(k, self.module.StaticTuple):
473
self.assertEqual(sorted(refs, key=key),
474
sorted(scanner.get_referents(k3), key=key))
472
476
def test_empty_is_singleton(self):
473
477
key = self.module.StaticTuple()
491
495
def test__c_intern_handles_refcount(self):
492
496
if self.module is _static_tuple_py:
493
return # Not applicable
497
return # Not applicable
494
498
unique_str1 = 'unique str ' + osutils.rand_chars(20)
495
499
unique_str2 = 'unique str ' + osutils.rand_chars(20)
496
500
key = self.module.StaticTuple(unique_str1, unique_str2)
526
530
def test__c_keys_are_not_immortal(self):
527
531
if self.module is _static_tuple_py:
528
return # Not applicable
532
return # Not applicable
529
533
unique_str1 = 'unique str ' + osutils.rand_chars(20)
530
534
unique_str2 = 'unique str ' + osutils.rand_chars(20)
531
535
key = self.module.StaticTuple(unique_str1, unique_str2)
597
601
def test_pickle(self):
598
602
st = self.module.StaticTuple('foo', 'bar')
599
pickled = cPickle.dumps(st)
600
unpickled = cPickle.loads(pickled)
603
pickled = pickle.dumps(st)
604
unpickled = pickle.loads(pickled)
601
605
self.assertEqual(unpickled, st)
603
607
def test_pickle_empty(self):
604
608
st = self.module.StaticTuple()
605
pickled = cPickle.dumps(st)
606
unpickled = cPickle.loads(pickled)
609
pickled = pickle.dumps(st)
610
unpickled = pickle.loads(pickled)
607
611
self.assertIs(st, unpickled)
609
613
def test_pickle_nested(self):
610
614
st = self.module.StaticTuple('foo', self.module.StaticTuple('bar'))
611
pickled = cPickle.dumps(st)
612
unpickled = cPickle.loads(pickled)
615
pickled = pickle.dumps(st)
616
unpickled = pickle.loads(pickled)
613
617
self.assertEqual(unpickled, st)
615
619
def test_static_tuple_thunk(self):
616
620
# Make sure the right implementation is available from
617
# bzrlib.static_tuple.StaticTuple.
621
# breezy.static_tuple.StaticTuple.
618
622
if self.module is _static_tuple_py:
619
623
if compiled_static_tuple_feature.available():
620
624
# We will be using the C version