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)
457
446
self.assertEqual(sorted(refs), sorted(scanner.get_referents(k)))
459
448
def test_nested_referents(self):
460
self.requireFeature(Meliae)
449
self.requireFeature(features.meliae)
461
450
from meliae import scanner
462
451
strs = ['foo', 'bar', 'baz', 'bing']
463
452
k1 = self.module.StaticTuple(*strs[:2])
491
480
def test__c_intern_handles_refcount(self):
492
481
if self.module is _static_tuple_py:
493
return # Not applicable
482
return # Not applicable
494
483
unique_str1 = 'unique str ' + osutils.rand_chars(20)
495
484
unique_str2 = 'unique str ' + osutils.rand_chars(20)
496
485
key = self.module.StaticTuple(unique_str1, unique_str2)
526
515
def test__c_keys_are_not_immortal(self):
527
516
if self.module is _static_tuple_py:
528
return # Not applicable
517
return # Not applicable
529
518
unique_str1 = 'unique str ' + osutils.rand_chars(20)
530
519
unique_str2 = 'unique str ' + osutils.rand_chars(20)
531
520
key = self.module.StaticTuple(unique_str1, unique_str2)
597
586
def test_pickle(self):
598
587
st = self.module.StaticTuple('foo', 'bar')
599
pickled = cPickle.dumps(st)
600
unpickled = cPickle.loads(pickled)
588
pickled = pickle.dumps(st)
589
unpickled = pickle.loads(pickled)
601
590
self.assertEqual(unpickled, st)
603
592
def test_pickle_empty(self):
604
593
st = self.module.StaticTuple()
605
pickled = cPickle.dumps(st)
606
unpickled = cPickle.loads(pickled)
594
pickled = pickle.dumps(st)
595
unpickled = pickle.loads(pickled)
607
596
self.assertIs(st, unpickled)
609
598
def test_pickle_nested(self):
610
599
st = self.module.StaticTuple('foo', self.module.StaticTuple('bar'))
611
pickled = cPickle.dumps(st)
612
unpickled = cPickle.loads(pickled)
600
pickled = pickle.dumps(st)
601
unpickled = pickle.loads(pickled)
613
602
self.assertEqual(unpickled, st)
615
604
def test_static_tuple_thunk(self):
616
605
# Make sure the right implementation is available from
617
# bzrlib.static_tuple.StaticTuple.
606
# breezy.static_tuple.StaticTuple.
618
607
if self.module is _static_tuple_py:
619
608
if compiled_static_tuple_feature.available():
620
609
# We will be using the C version