1
# Copyright (C) 2009 Canonical Ltd
3
# This program is free software; you can redistribute it and/or modify
4
# it under the terms of the GNU General Public License as published by
5
# the Free Software Foundation; either version 2 of the License, or
6
# (at your option) any later version.
8
# This program is distributed in the hope that it will be useful,
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11
# GNU General Public License for more details.
13
# You should have received a copy of the GNU General Public License
14
# along with this program; if not, write to the Free Software
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17
"""Tests for the StaticTuple type."""
30
def load_tests(standard_tests, module, loader):
31
"""Parameterize tests for all versions of groupcompress."""
33
('python', {'module': _static_tuple_py}),
35
suite = loader.suiteClass()
36
if CompiledStaticTuple.available():
37
from bzrlib import _static_tuple_c
38
scenarios.append(('C', {'module': _static_tuple_c}))
40
# the compiled module isn't available, so we add a failing test
41
class FailWithoutFeature(tests.TestCase):
43
self.requireFeature(CompiledStaticTuple)
44
suite.addTest(loader.loadTestsFromTestCase(FailWithoutFeature))
45
result = tests.multiply_tests(standard_tests, scenarios, suite)
49
class _CompiledStaticTuple(tests.Feature):
53
import bzrlib._static_tuple_c
58
def feature_name(self):
59
return 'bzrlib._static_tuple_c'
61
CompiledStaticTuple = _CompiledStaticTuple()
64
class _Meliae(tests.Feature):
68
from meliae import scanner
73
def feature_name(self):
74
return "Meliae - python memory debugger"
79
class TestStaticTuple(tests.TestCase):
81
def test_create(self):
82
k = self.module.StaticTuple('foo')
83
k = self.module.StaticTuple('foo', 'bar')
85
def test_create_bad_args(self):
88
self.assertRaises(ValueError, self.module.StaticTuple, *args_256)
90
self.assertRaises(ValueError, self.module.StaticTuple, *args_300)
92
self.assertRaises(TypeError, self.module.StaticTuple, 10)
94
def test_as_tuple(self):
95
k = self.module.StaticTuple('foo')
97
self.assertEqual(('foo',), t)
98
k = self.module.StaticTuple('foo', 'bar')
100
self.assertEqual(('foo', 'bar'), t)
103
k = self.module.StaticTuple()
104
self.assertEqual(0, len(k))
105
k = self.module.StaticTuple('foo')
106
self.assertEqual(1, len(k))
107
k = self.module.StaticTuple('foo', 'bar')
108
self.assertEqual(2, len(k))
109
k = self.module.StaticTuple('foo', 'bar', 'b', 'b', 'b', 'b', 'b')
110
self.assertEqual(7, len(k))
112
k = self.module.StaticTuple(*args)
113
self.assertEqual(255, len(k))
115
def test_hold_other_static_tuples(self):
116
k = self.module.StaticTuple('foo', 'bar')
117
k2 = self.module.StaticTuple(k, k)
118
self.assertEqual(2, len(k2))
119
self.assertIs(k, k2[0])
120
self.assertIs(k, k2[1])
122
def test_getitem(self):
123
k = self.module.StaticTuple('foo', 'bar', 'b', 'b', 'b', 'b', 'z')
124
self.assertEqual('foo', k[0])
125
self.assertEqual('foo', k[0])
126
self.assertEqual('foo', k[0])
127
self.assertEqual('z', k[6])
128
self.assertEqual('z', k[-1])
130
def test_refcount(self):
132
num_refs = sys.getrefcount(f)
133
k = self.module.StaticTuple(f)
134
self.assertEqual(num_refs + 1, sys.getrefcount(f))
136
self.assertEqual(num_refs + 2, sys.getrefcount(f))
138
self.assertEqual(num_refs + 2, sys.getrefcount(f))
140
self.assertEqual(num_refs + 3, sys.getrefcount(f))
142
self.assertEqual(num_refs + 1, sys.getrefcount(f))
144
self.assertEqual(num_refs, sys.getrefcount(f))
146
def test__repr__(self):
147
k = self.module.StaticTuple('foo', 'bar', 'baz', 'bing')
148
self.assertEqual("('foo', 'bar', 'baz', 'bing')", repr(k))
150
def assertCompareEqual(self, k1, k2):
151
self.assertTrue(k1 == k2)
152
self.assertTrue(k1 <= k2)
153
self.assertTrue(k1 >= k2)
154
self.assertFalse(k1 != k2)
155
self.assertFalse(k1 < k2)
156
self.assertFalse(k1 > k2)
158
def test_compare_same_obj(self):
159
k1 = self.module.StaticTuple('foo', 'bar')
160
self.assertCompareEqual(k1, k1)
161
k2 = self.module.StaticTuple(k1, k1)
162
self.assertCompareEqual(k2, k2)
164
def test_compare_equivalent_obj(self):
165
k1 = self.module.StaticTuple('foo', 'bar')
166
k2 = self.module.StaticTuple('foo', 'bar')
167
self.assertCompareEqual(k1, k2)
168
k3 = self.module.StaticTuple(k1, k2)
169
k4 = self.module.StaticTuple(k2, k1)
170
self.assertCompareEqual(k1, k2)
172
def test_compare_similar_obj(self):
173
k1 = self.module.StaticTuple('foo' + ' bar', 'bar' + ' baz')
174
k2 = self.module.StaticTuple('fo' + 'o bar', 'ba' + 'r baz')
175
self.assertCompareEqual(k1, k2)
176
k3 = self.module.StaticTuple('foo ' + 'bar', 'bar ' + 'baz')
177
k4 = self.module.StaticTuple('f' + 'oo bar', 'b' + 'ar baz')
178
k5 = self.module.StaticTuple(k1, k2)
179
k6 = self.module.StaticTuple(k3, k4)
180
self.assertCompareEqual(k5, k6)
182
def assertCompareDifferent(self, k_small, k_big):
183
self.assertFalse(k_small == k_big)
184
self.assertFalse(k_small >= k_big)
185
self.assertFalse(k_small > k_big)
186
self.assertTrue(k_small != k_big)
187
self.assertTrue(k_small <= k_big)
188
self.assertTrue(k_small < k_big)
190
def test_compare_vs_none(self):
191
k1 = self.module.StaticTuple('baz', 'bing')
192
self.assertCompareDifferent(None, k1)
193
self.assertCompareDifferent(10, k1)
194
# Comparison with a string is poorly-defined, I seem to get failures
195
# regardless of which one comes first...
196
# self.assertCompareDifferent('baz', k1)
198
def test_compare_all_different_same_width(self):
199
k1 = self.module.StaticTuple('baz', 'bing')
200
k2 = self.module.StaticTuple('foo', 'bar')
201
self.assertCompareDifferent(k1, k2)
202
k3 = self.module.StaticTuple(k1, k2)
203
k4 = self.module.StaticTuple(k2, k1)
204
self.assertCompareDifferent(k3, k4)
206
def test_compare_some_different(self):
207
k1 = self.module.StaticTuple('foo', 'bar')
208
k2 = self.module.StaticTuple('foo', 'zzz')
209
self.assertCompareDifferent(k1, k2)
210
k3 = self.module.StaticTuple(k1, k1)
211
k4 = self.module.StaticTuple(k1, k2)
212
self.assertCompareDifferent(k3, k4)
214
def test_compare_diff_width(self):
215
k1 = self.module.StaticTuple('foo')
216
k2 = self.module.StaticTuple('foo', 'bar')
217
self.assertCompareDifferent(k1, k2)
218
k3 = self.module.StaticTuple(k1)
219
k4 = self.module.StaticTuple(k1, k2)
220
self.assertCompareDifferent(k3, k4)
222
def test_compare_to_tuples(self):
223
k1 = self.module.StaticTuple('foo')
224
self.assertCompareEqual(k1, ('foo',))
225
self.assertCompareEqual(('foo',), k1)
226
self.assertCompareDifferent(k1, ('foo', 'bar'))
227
self.assertCompareDifferent(k1, ('foo', 10))
229
k2 = self.module.StaticTuple('foo', 'bar')
230
self.assertCompareEqual(k2, ('foo', 'bar'))
231
self.assertCompareEqual(('foo', 'bar'), k2)
232
self.assertCompareDifferent(k2, ('foo', 'zzz'))
233
self.assertCompareDifferent(('foo',), k2)
234
self.assertCompareDifferent(('foo', 'aaa'), k2)
235
self.assertCompareDifferent(('baz', 'bing'), k2)
236
self.assertCompareDifferent(('foo', 10), k2)
238
k3 = self.module.StaticTuple(k1, k2)
239
self.assertCompareEqual(k3, (('foo',), ('foo', 'bar')))
240
self.assertCompareEqual((('foo',), ('foo', 'bar')), k3)
241
self.assertCompareEqual(k3, (k1, ('foo', 'bar')))
242
self.assertCompareEqual((k1, ('foo', 'bar')), k3)
245
k = self.module.StaticTuple('foo')
246
self.assertEqual(hash(k), hash(('foo',)))
247
k = self.module.StaticTuple('foo', 'bar', 'baz', 'bing')
248
as_tuple = ('foo', 'bar', 'baz', 'bing')
249
self.assertEqual(hash(k), hash(as_tuple))
251
# Because k == , it replaces the slot, rather than having both
252
# present in the dict.
253
self.assertEqual('foo', x[as_tuple])
255
self.assertEqual({as_tuple: 'bar'}, x)
257
k2 = self.module.StaticTuple(k)
258
as_tuple2 = (('foo', 'bar', 'baz', 'bing'),)
259
self.assertEqual(hash(k2), hash(as_tuple2))
261
def test_slice(self):
262
k = self.module.StaticTuple('foo', 'bar', 'baz', 'bing')
263
self.assertEqual(('foo', 'bar'), k[:2])
264
self.assertEqual(('baz',), k[2:-1])
266
def test_referents(self):
267
# We implement tp_traverse so that things like 'meliae' can measure the
268
# amount of referenced memory. Unfortunately gc.get_referents() first
269
# checks the IS_GC flag before it traverses anything. So there isn't a
270
# way to expose it that I can see.
271
self.requireFeature(Meliae)
272
from meliae import scanner
273
strs = ['foo', 'bar', 'baz', 'bing']
274
k = self.module.StaticTuple(*strs)
275
if self.module is _static_tuple_py:
276
# The python version references objects slightly different than the
278
self.assertEqual([k._tuple, _static_tuple_py.StaticTuple],
279
scanner.get_referents(k))
280
self.assertEqual(sorted(strs),
281
sorted(scanner.get_referents(k._tuple)))
283
self.assertEqual(sorted(strs), sorted(scanner.get_referents(k)))
285
def test_nested_referents(self):
286
self.requireFeature(Meliae)
288
def test_empty_is_singleton(self):
289
self.requireFeature(Meliae)
290
from meliae import scanner
291
key = self.module.StaticTuple()
292
self.assertIs(key, self.module._empty_tuple)
293
strs = ['foo', 'bar', 'baz', 'bing']
294
k1 = self.module.StaticTuple(*strs[:2])
295
k2 = self.module.StaticTuple(*strs[2:])
296
k3 = self.module.StaticTuple(k1, k2)
297
if self.module is _static_tuple_py:
298
# The python version references objects slightly different than the
300
self.assertEqual([k3._tuple, _static_tuple_py.StaticTuple],
301
scanner.get_referents(k3))
302
self.assertEqual(sorted([k1, k2]),
303
sorted(scanner.get_referents(k3._tuple)))
305
self.assertEqual(sorted([k1, k2]),
306
sorted(scanner.get_referents(k3)))
308
def test_intern(self):
309
unique_str1 = 'unique str ' + osutils.rand_chars(20)
310
unique_str2 = 'unique str ' + osutils.rand_chars(20)
311
key = self.module.StaticTuple(unique_str1, unique_str2)
312
self.assertFalse(key in self.module._interned_tuples)
313
key2 = self.module.StaticTuple(unique_str1, unique_str2)
314
self.assertEqual(key, key2)
315
self.assertIsNot(key, key2)
317
self.assertIs(key, key3)
318
self.assertTrue(key in self.module._interned_tuples)
319
self.assertEqual(key, self.module._interned_tuples[key])
321
self.assertIs(key, key2)
323
def test__c_intern_handles_refcount(self):
324
if self.module is _static_tuple_py:
325
return # Not applicable
326
unique_str1 = 'unique str ' + osutils.rand_chars(20)
327
unique_str2 = 'unique str ' + osutils.rand_chars(20)
328
key = self.module.StaticTuple(unique_str1, unique_str2)
329
self.assertFalse(key in self.module._interned_tuples)
330
self.assertFalse(key._is_interned())
331
key2 = self.module.StaticTuple(unique_str1, unique_str2)
332
self.assertEqual(key, key2)
333
self.assertIsNot(key, key2)
334
refcount = sys.getrefcount(key)
335
self.assertEqual(2, refcount)
338
self.assertIs(key, key3)
339
self.assertTrue(key in self.module._interned_tuples)
340
self.assertEqual(key, self.module._interned_tuples[key])
342
# We should not increase the refcount just via 'intern'
343
self.assertEqual(2, sys.getrefcount(key))
344
self.assertTrue(key._is_interned())
346
# We have one more ref in 'key2' but otherwise no extra refs
347
self.assertEqual(3, sys.getrefcount(key))
348
self.assertIs(key, key2)
350
def test__c_keys_are_not_immortal(self):
351
if self.module is _static_tuple_py:
352
return # Not applicable
353
unique_str1 = 'unique str ' + osutils.rand_chars(20)
354
unique_str2 = 'unique str ' + osutils.rand_chars(20)
355
key = self.module.StaticTuple(unique_str1, unique_str2)
356
self.assertFalse(key in self.module._interned_tuples)
357
self.assertEqual(2, sys.getrefcount(key))
359
self.assertEqual(2, sys.getrefcount(key))
360
self.assertTrue(key in self.module._interned_tuples)
361
self.assertTrue(key._is_interned())
363
# Create a new entry, which would point to the same location
364
key = self.module.StaticTuple(unique_str1, unique_str2)
365
self.assertEqual(2, sys.getrefcount(key))
366
# This old entry in _interned_tuples should be gone
367
self.assertFalse(key in self.module._interned_tuples)
368
self.assertFalse(key._is_interned())
370
def test__c_has_C_API(self):
371
if self.module is _static_tuple_py:
373
self.assertIsNot(None, self.module._C_API)