/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar

« back to all changes in this revision

Viewing changes to bzrlib/tests/test__static_tuple.py

  • Committer: Vincent Ladeuil
  • Date: 2012-01-18 14:09:19 UTC
  • mto: This revision was merged to the branch mainline in revision 6468.
  • Revision ID: v.ladeuil+lp@free.fr-20120118140919-rlvdrhpc0nq1lbwi
Change set/remove to require a lock for the branch config files.

This means that tests (or any plugin for that matter) do not requires an
explicit lock on the branch anymore to change a single option. This also
means the optimisation becomes "opt-in" and as such won't be as
spectacular as it may be and/or harder to get right (nothing fails
anymore).

This reduces the diff by ~300 lines.

Code/tests that were updating more than one config option is still taking
a lock to at least avoid some IOs and demonstrate the benefits through
the decreased number of hpss calls.

The duplication between BranchStack and BranchOnlyStack will be removed
once the same sharing is in place for local config files, at which point
the Stack class itself may be able to host the changes.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# Copyright (C) 2009, 2010, 2011 Canonical Ltd
 
2
#
 
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.
 
7
#
 
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.
 
12
#
 
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
 
16
 
 
17
"""Tests for the StaticTuple type."""
 
18
 
 
19
import cPickle
 
20
import sys
 
21
 
 
22
from bzrlib import (
 
23
    _static_tuple_py,
 
24
    debug,
 
25
    osutils,
 
26
    static_tuple,
 
27
    tests,
 
28
    )
 
29
from bzrlib.tests import (
 
30
    features,
 
31
    )
 
32
 
 
33
 
 
34
def load_tests(standard_tests, module, loader):
 
35
    """Parameterize tests for all versions of groupcompress."""
 
36
    global compiled_static_tuple_feature
 
37
    suite, compiled_static_tuple_feature = tests.permute_tests_for_extension(
 
38
        standard_tests, loader, 'bzrlib._static_tuple_py',
 
39
        'bzrlib._static_tuple_c')
 
40
    return suite
 
41
 
 
42
 
 
43
class TestStaticTuple(tests.TestCase):
 
44
 
 
45
    def assertRefcount(self, count, obj):
 
46
        """Assert that the refcount for obj is what we expect.
 
47
 
 
48
        Note that this automatically adjusts for the fact that calling
 
49
        assertRefcount actually creates a new pointer, as does calling
 
50
        sys.getrefcount. So pass the expected value *before* the call.
 
51
        """
 
52
        # I don't understand why it is getrefcount()-3 here, but it seems to be
 
53
        # correct. If I check in the calling function, with:
 
54
        # self.assertEqual(count, sys.getrefcount(obj)-1)
 
55
        # Then it works fine. Something about passing it to assertRefcount is
 
56
        # actually double-incrementing (and decrementing) the refcount
 
57
        self.assertEqual(count, sys.getrefcount(obj)-3)
 
58
 
 
59
    def test_create(self):
 
60
        k = self.module.StaticTuple('foo')
 
61
        k = self.module.StaticTuple('foo', 'bar')
 
62
 
 
63
    def test_create_bad_args(self):
 
64
        args_256 = ['a']*256
 
65
        # too many args
 
66
        self.assertRaises(TypeError, self.module.StaticTuple, *args_256)
 
67
        args_300 = ['a']*300
 
68
        self.assertRaises(TypeError, self.module.StaticTuple, *args_300)
 
69
        # not a string
 
70
        self.assertRaises(TypeError, self.module.StaticTuple, object())
 
71
 
 
72
    def test_concat(self):
 
73
        st1 = self.module.StaticTuple('foo')
 
74
        st2 = self.module.StaticTuple('bar')
 
75
        st3 = self.module.StaticTuple('foo', 'bar')
 
76
        st4 = st1 + st2
 
77
        self.assertEqual(st3, st4)
 
78
        self.assertIsInstance(st4, self.module.StaticTuple)
 
79
 
 
80
    def test_concat_with_tuple(self):
 
81
        st1 = self.module.StaticTuple('foo')
 
82
        t2 = ('bar',)
 
83
        st3 = self.module.StaticTuple('foo', 'bar')
 
84
        st4 = self.module.StaticTuple('bar', 'foo')
 
85
        st5 = st1 + t2
 
86
        st6 = t2 + st1
 
87
        self.assertEqual(st3, st5)
 
88
        self.assertIsInstance(st5, self.module.StaticTuple)
 
89
        self.assertEqual(st4, st6)
 
90
        if self.module is _static_tuple_py:
 
91
            # _static_tuple_py has StaticTuple(tuple), so tuple thinks it
 
92
            # already knows how to concatenate, as such we can't "inject" our
 
93
            # own concatenation...
 
94
            self.assertIsInstance(st6, tuple)
 
95
        else:
 
96
            self.assertIsInstance(st6, self.module.StaticTuple)
 
97
 
 
98
    def test_concat_with_bad_tuple(self):
 
99
        st1 = self.module.StaticTuple('foo')
 
100
        t2 = (object(),)
 
101
        # Using st1.__add__ doesn't give the same results as doing the '+' form
 
102
        self.assertRaises(TypeError, lambda: st1 + t2)
 
103
 
 
104
    def test_concat_with_non_tuple(self):
 
105
        st1 = self.module.StaticTuple('foo')
 
106
        self.assertRaises(TypeError, lambda: st1 + 10)
 
107
        
 
108
    def test_as_tuple(self):
 
109
        k = self.module.StaticTuple('foo')
 
110
        t = k.as_tuple()
 
111
        self.assertEqual(('foo',), t)
 
112
        self.assertIsInstance(t, tuple)
 
113
        self.assertFalse(isinstance(t, self.module.StaticTuple))
 
114
        k = self.module.StaticTuple('foo', 'bar')
 
115
        t = k.as_tuple()
 
116
        self.assertEqual(('foo', 'bar'), t)
 
117
        k2 = self.module.StaticTuple(1, k)
 
118
        t = k2.as_tuple()
 
119
        self.assertIsInstance(t, tuple)
 
120
        # For pickling to work, we need to keep the sub-items as StaticTuple so
 
121
        # that it knows that they also need to be converted.
 
122
        self.assertIsInstance(t[1], self.module.StaticTuple)
 
123
        self.assertEqual((1, ('foo', 'bar')), t)
 
124
 
 
125
    def test_as_tuples(self):
 
126
        k1 = self.module.StaticTuple('foo', 'bar')
 
127
        t = static_tuple.as_tuples(k1)
 
128
        self.assertIsInstance(t, tuple)
 
129
        self.assertEqual(('foo', 'bar'), t)
 
130
        k2 = self.module.StaticTuple(1, k1)
 
131
        t = static_tuple.as_tuples(k2)
 
132
        self.assertIsInstance(t, tuple)
 
133
        self.assertIsInstance(t[1], tuple)
 
134
        self.assertEqual((1, ('foo', 'bar')), t)
 
135
        mixed = (1, k1)
 
136
        t = static_tuple.as_tuples(mixed)
 
137
        self.assertIsInstance(t, tuple)
 
138
        self.assertIsInstance(t[1], tuple)
 
139
        self.assertEqual((1, ('foo', 'bar')), t)
 
140
 
 
141
    def test_len(self):
 
142
        k = self.module.StaticTuple()
 
143
        self.assertEqual(0, len(k))
 
144
        k = self.module.StaticTuple('foo')
 
145
        self.assertEqual(1, len(k))
 
146
        k = self.module.StaticTuple('foo', 'bar')
 
147
        self.assertEqual(2, len(k))
 
148
        k = self.module.StaticTuple('foo', 'bar', 'b', 'b', 'b', 'b', 'b')
 
149
        self.assertEqual(7, len(k))
 
150
        args = ['foo']*255
 
151
        k = self.module.StaticTuple(*args)
 
152
        self.assertEqual(255, len(k))
 
153
 
 
154
    def test_hold_other_static_tuples(self):
 
155
        k = self.module.StaticTuple('foo', 'bar')
 
156
        k2 = self.module.StaticTuple(k, k)
 
157
        self.assertEqual(2, len(k2))
 
158
        self.assertIs(k, k2[0])
 
159
        self.assertIs(k, k2[1])
 
160
 
 
161
    def test_getitem(self):
 
162
        k = self.module.StaticTuple('foo', 'bar', 'b', 'b', 'b', 'b', 'z')
 
163
        self.assertEqual('foo', k[0])
 
164
        self.assertEqual('foo', k[0])
 
165
        self.assertEqual('foo', k[0])
 
166
        self.assertEqual('z', k[6])
 
167
        self.assertEqual('z', k[-1])
 
168
        self.assertRaises(IndexError, k.__getitem__, 7)
 
169
        self.assertRaises(IndexError, k.__getitem__, 256+7)
 
170
        self.assertRaises(IndexError, k.__getitem__, 12024)
 
171
        # Python's [] resolver handles the negative arguments, so we can't
 
172
        # really test StaticTuple_item() with negative values.
 
173
        self.assertRaises(TypeError, k.__getitem__, 'not-an-int')
 
174
        self.assertRaises(TypeError, k.__getitem__, '5')
 
175
 
 
176
    def test_refcount(self):
 
177
        f = 'fo' + 'oo'
 
178
        num_refs = sys.getrefcount(f) - 1 #sys.getrefcount() adds one
 
179
        k = self.module.StaticTuple(f)
 
180
        self.assertRefcount(num_refs + 1, f)
 
181
        b = k[0]
 
182
        self.assertRefcount(num_refs + 2, f)
 
183
        b = k[0]
 
184
        self.assertRefcount(num_refs + 2, f)
 
185
        c = k[0]
 
186
        self.assertRefcount(num_refs + 3, f)
 
187
        del b, c
 
188
        self.assertRefcount(num_refs + 1, f)
 
189
        del k
 
190
        self.assertRefcount(num_refs, f)
 
191
 
 
192
    def test__repr__(self):
 
193
        k = self.module.StaticTuple('foo', 'bar', 'baz', 'bing')
 
194
        self.assertEqual("StaticTuple('foo', 'bar', 'baz', 'bing')", repr(k))
 
195
 
 
196
    def assertCompareEqual(self, k1, k2):
 
197
        self.assertTrue(k1 == k2)
 
198
        self.assertTrue(k1 <= k2)
 
199
        self.assertTrue(k1 >= k2)
 
200
        self.assertFalse(k1 != k2)
 
201
        self.assertFalse(k1 < k2)
 
202
        self.assertFalse(k1 > k2)
 
203
 
 
204
    def test_holds_None(self):
 
205
        k1 = self.module.StaticTuple(None)
 
206
        # You cannot subclass None anyway
 
207
 
 
208
    def test_holds_int(self):
 
209
        k1 = self.module.StaticTuple(1)
 
210
        class subint(int):
 
211
            pass
 
212
        # But not a subclass, because subint could introduce refcycles
 
213
        self.assertRaises(TypeError, self.module.StaticTuple, subint(2))
 
214
 
 
215
    def test_holds_long(self):
 
216
        k1 = self.module.StaticTuple(2L**65)
 
217
        class sublong(long):
 
218
            pass
 
219
        # But not a subclass
 
220
        self.assertRaises(TypeError, self.module.StaticTuple, sublong(1))
 
221
 
 
222
    def test_holds_float(self):
 
223
        k1 = self.module.StaticTuple(1.2)
 
224
        class subfloat(float):
 
225
            pass
 
226
        self.assertRaises(TypeError, self.module.StaticTuple, subfloat(1.5))
 
227
 
 
228
    def test_holds_str(self):
 
229
        k1 = self.module.StaticTuple('astring')
 
230
        class substr(str):
 
231
            pass
 
232
        self.assertRaises(TypeError, self.module.StaticTuple, substr('a'))
 
233
 
 
234
    def test_holds_unicode(self):
 
235
        k1 = self.module.StaticTuple(u'\xb5')
 
236
        class subunicode(unicode):
 
237
            pass
 
238
        self.assertRaises(TypeError, self.module.StaticTuple,
 
239
                          subunicode(u'\xb5'))
 
240
 
 
241
    def test_hold_bool(self):
 
242
        k1 = self.module.StaticTuple(True)
 
243
        k2 = self.module.StaticTuple(False)
 
244
        # Cannot subclass bool
 
245
 
 
246
    def test_compare_same_obj(self):
 
247
        k1 = self.module.StaticTuple('foo', 'bar')
 
248
        self.assertCompareEqual(k1, k1)
 
249
        k2 = self.module.StaticTuple(k1, k1)
 
250
        self.assertCompareEqual(k2, k2)
 
251
        k3 = self.module.StaticTuple('foo', 1, None, u'\xb5', 1.2, 2**65, True,
 
252
                                     k1)
 
253
        self.assertCompareEqual(k3, k3)
 
254
 
 
255
    def test_compare_equivalent_obj(self):
 
256
        k1 = self.module.StaticTuple('foo', 'bar')
 
257
        k2 = self.module.StaticTuple('foo', 'bar')
 
258
        self.assertCompareEqual(k1, k2)
 
259
        k3 = self.module.StaticTuple(k1, k2)
 
260
        k4 = self.module.StaticTuple(k2, k1)
 
261
        self.assertCompareEqual(k1, k2)
 
262
        k5 = self.module.StaticTuple('foo', 1, None, u'\xb5', 1.2, 2**65, True,
 
263
                                     k1)
 
264
        k6 = self.module.StaticTuple('foo', 1, None, u'\xb5', 1.2, 2**65, True,
 
265
                                     k1)
 
266
        self.assertCompareEqual(k5, k6)
 
267
        k7 = self.module.StaticTuple(None)
 
268
        k8 = self.module.StaticTuple(None)
 
269
        self.assertCompareEqual(k7, k8)
 
270
 
 
271
    def test_compare_similar_obj(self):
 
272
        k1 = self.module.StaticTuple('foo' + ' bar', 'bar' + ' baz')
 
273
        k2 = self.module.StaticTuple('fo' + 'o bar', 'ba' + 'r baz')
 
274
        self.assertCompareEqual(k1, k2)
 
275
        k3 = self.module.StaticTuple('foo ' + 'bar', 'bar ' + 'baz')
 
276
        k4 = self.module.StaticTuple('f' + 'oo bar', 'b' + 'ar baz')
 
277
        k5 = self.module.StaticTuple(k1, k2)
 
278
        k6 = self.module.StaticTuple(k3, k4)
 
279
        self.assertCompareEqual(k5, k6)
 
280
 
 
281
    def assertCompareDifferent(self, k_small, k_big):
 
282
        self.assertFalse(k_small == k_big)
 
283
        self.assertFalse(k_small >= k_big)
 
284
        self.assertFalse(k_small > k_big)
 
285
        self.assertTrue(k_small != k_big)
 
286
        self.assertTrue(k_small <= k_big)
 
287
        self.assertTrue(k_small < k_big)
 
288
 
 
289
    def assertCompareNoRelation(self, k1, k2):
 
290
        """Run the comparison operators, make sure they do something.
 
291
 
 
292
        However, we don't actually care what comes first or second. This is
 
293
        stuff like cross-class comparisons. We don't want to segfault/raise an
 
294
        exception, but we don't care about the sort order.
 
295
        """
 
296
        self.assertFalse(k1 == k2)
 
297
        self.assertTrue(k1 != k2)
 
298
        # Do the comparison, but we don't care about the result
 
299
        k1 >= k2
 
300
        k1 > k2
 
301
        k1 <= k2
 
302
        k1 < k2
 
303
 
 
304
    def test_compare_vs_none(self):
 
305
        k1 = self.module.StaticTuple('baz', 'bing')
 
306
        self.assertCompareDifferent(None, k1)
 
307
    
 
308
    def test_compare_cross_class(self):
 
309
        k1 = self.module.StaticTuple('baz', 'bing')
 
310
        self.assertCompareNoRelation(10, k1)
 
311
        self.assertCompareNoRelation('baz', k1)
 
312
 
 
313
    def test_compare_all_different_same_width(self):
 
314
        k1 = self.module.StaticTuple('baz', 'bing')
 
315
        k2 = self.module.StaticTuple('foo', 'bar')
 
316
        self.assertCompareDifferent(k1, k2)
 
317
        k3 = self.module.StaticTuple(k1, k2)
 
318
        k4 = self.module.StaticTuple(k2, k1)
 
319
        self.assertCompareDifferent(k3, k4)
 
320
        k5 = self.module.StaticTuple(1)
 
321
        k6 = self.module.StaticTuple(2)
 
322
        self.assertCompareDifferent(k5, k6)
 
323
        k7 = self.module.StaticTuple(1.2)
 
324
        k8 = self.module.StaticTuple(2.4)
 
325
        self.assertCompareDifferent(k7, k8)
 
326
        k9 = self.module.StaticTuple(u's\xb5')
 
327
        k10 = self.module.StaticTuple(u's\xe5')
 
328
        self.assertCompareDifferent(k9, k10)
 
329
 
 
330
    def test_compare_some_different(self):
 
331
        k1 = self.module.StaticTuple('foo', 'bar')
 
332
        k2 = self.module.StaticTuple('foo', 'zzz')
 
333
        self.assertCompareDifferent(k1, k2)
 
334
        k3 = self.module.StaticTuple(k1, k1)
 
335
        k4 = self.module.StaticTuple(k1, k2)
 
336
        self.assertCompareDifferent(k3, k4)
 
337
        k5 = self.module.StaticTuple('foo', None)
 
338
        self.assertCompareDifferent(k5, k1)
 
339
        self.assertCompareDifferent(k5, k2)
 
340
 
 
341
    def test_compare_diff_width(self):
 
342
        k1 = self.module.StaticTuple('foo')
 
343
        k2 = self.module.StaticTuple('foo', 'bar')
 
344
        self.assertCompareDifferent(k1, k2)
 
345
        k3 = self.module.StaticTuple(k1)
 
346
        k4 = self.module.StaticTuple(k1, k2)
 
347
        self.assertCompareDifferent(k3, k4)
 
348
 
 
349
    def test_compare_different_types(self):
 
350
        k1 = self.module.StaticTuple('foo', 'bar')
 
351
        k2 = self.module.StaticTuple('foo', 1, None, u'\xb5', 1.2, 2**65, True,
 
352
                                     k1)
 
353
        self.assertCompareNoRelation(k1, k2)
 
354
        k3 = self.module.StaticTuple('foo')
 
355
        self.assertCompareDifferent(k3, k1)
 
356
        k4 = self.module.StaticTuple(None)
 
357
        self.assertCompareDifferent(k4, k1)
 
358
        k5 = self.module.StaticTuple(1)
 
359
        self.assertCompareNoRelation(k1, k5)
 
360
 
 
361
    def test_compare_to_tuples(self):
 
362
        k1 = self.module.StaticTuple('foo')
 
363
        self.assertCompareEqual(k1, ('foo',))
 
364
        self.assertCompareEqual(('foo',), k1)
 
365
        self.assertCompareDifferent(k1, ('foo', 'bar'))
 
366
        self.assertCompareDifferent(k1, ('foo', 10))
 
367
 
 
368
        k2 = self.module.StaticTuple('foo', 'bar')
 
369
        self.assertCompareEqual(k2, ('foo', 'bar'))
 
370
        self.assertCompareEqual(('foo', 'bar'), k2)
 
371
        self.assertCompareDifferent(k2, ('foo', 'zzz'))
 
372
        self.assertCompareDifferent(('foo',), k2)
 
373
        self.assertCompareDifferent(('foo', 'aaa'), k2)
 
374
        self.assertCompareDifferent(('baz', 'bing'), k2)
 
375
        self.assertCompareDifferent(('foo', 10), k2)
 
376
 
 
377
        k3 = self.module.StaticTuple(k1, k2)
 
378
        self.assertCompareEqual(k3, (('foo',), ('foo', 'bar')))
 
379
        self.assertCompareEqual((('foo',), ('foo', 'bar')), k3)
 
380
        self.assertCompareEqual(k3, (k1, ('foo', 'bar')))
 
381
        self.assertCompareEqual((k1, ('foo', 'bar')), k3)
 
382
 
 
383
    def test_compare_mixed_depths(self):
 
384
        stuple = self.module.StaticTuple
 
385
        k1 = stuple(stuple('a',), stuple('b',))
 
386
        k2 = stuple(stuple(stuple('c',), stuple('d',)),
 
387
                    stuple('b',))
 
388
        # This requires comparing a StaticTuple to a 'string', and then
 
389
        # interpreting that value in the next higher StaticTuple. This used to
 
390
        # generate a PyErr_BadIternalCall. We now fall back to *something*.
 
391
        self.assertCompareNoRelation(k1, k2)
 
392
 
 
393
    def test_hash(self):
 
394
        k = self.module.StaticTuple('foo')
 
395
        self.assertEqual(hash(k), hash(('foo',)))
 
396
        k = self.module.StaticTuple('foo', 'bar', 'baz', 'bing')
 
397
        as_tuple = ('foo', 'bar', 'baz', 'bing')
 
398
        self.assertEqual(hash(k), hash(as_tuple))
 
399
        x = {k: 'foo'}
 
400
        # Because k == , it replaces the slot, rather than having both
 
401
        # present in the dict.
 
402
        self.assertEqual('foo', x[as_tuple])
 
403
        x[as_tuple] = 'bar'
 
404
        self.assertEqual({as_tuple: 'bar'}, x)
 
405
 
 
406
        k2 = self.module.StaticTuple(k)
 
407
        as_tuple2 = (('foo', 'bar', 'baz', 'bing'),)
 
408
        self.assertEqual(hash(k2), hash(as_tuple2))
 
409
 
 
410
        k3 = self.module.StaticTuple('foo', 1, None, u'\xb5', 1.2, 2**65, True,
 
411
                                     k)
 
412
        as_tuple3 = ('foo', 1, None, u'\xb5', 1.2, 2**65, True, k)
 
413
        self.assertEqual(hash(as_tuple3), hash(k3))
 
414
 
 
415
    def test_slice(self):
 
416
        k = self.module.StaticTuple('foo', 'bar', 'baz', 'bing')
 
417
        self.assertEqual(('foo', 'bar'), k[:2])
 
418
        self.assertEqual(('baz',), k[2:-1])
 
419
        try:
 
420
            val = k[::2]
 
421
        except TypeError:
 
422
            # C implementation raises a TypeError, we don't need the
 
423
            # implementation yet, so allow this to pass
 
424
            pass
 
425
        else:
 
426
            # Python implementation uses a regular Tuple, so make sure it gives
 
427
            # the right result
 
428
            self.assertEqual(('foo', 'baz'), val)
 
429
 
 
430
    def test_referents(self):
 
431
        # We implement tp_traverse so that things like 'meliae' can measure the
 
432
        # amount of referenced memory. Unfortunately gc.get_referents() first
 
433
        # checks the IS_GC flag before it traverses anything. We could write a
 
434
        # helper func, but that won't work for the generic implementation...
 
435
        self.requireFeature(features.meliae)
 
436
        from meliae import scanner
 
437
        strs = ['foo', 'bar', 'baz', 'bing']
 
438
        k = self.module.StaticTuple(*strs)
 
439
        if self.module is _static_tuple_py:
 
440
            refs = strs + [self.module.StaticTuple]
 
441
        else:
 
442
            refs = strs
 
443
        self.assertEqual(sorted(refs), sorted(scanner.get_referents(k)))
 
444
 
 
445
    def test_nested_referents(self):
 
446
        self.requireFeature(features.meliae)
 
447
        from meliae import scanner
 
448
        strs = ['foo', 'bar', 'baz', 'bing']
 
449
        k1 = self.module.StaticTuple(*strs[:2])
 
450
        k2 = self.module.StaticTuple(*strs[2:])
 
451
        k3 = self.module.StaticTuple(k1, k2)
 
452
        refs = [k1, k2]
 
453
        if self.module is _static_tuple_py:
 
454
            refs.append(self.module.StaticTuple)
 
455
        self.assertEqual(sorted(refs),
 
456
                         sorted(scanner.get_referents(k3)))
 
457
 
 
458
    def test_empty_is_singleton(self):
 
459
        key = self.module.StaticTuple()
 
460
        self.assertIs(key, self.module._empty_tuple)
 
461
 
 
462
    def test_intern(self):
 
463
        unique_str1 = 'unique str ' + osutils.rand_chars(20)
 
464
        unique_str2 = 'unique str ' + osutils.rand_chars(20)
 
465
        key = self.module.StaticTuple(unique_str1, unique_str2)
 
466
        self.assertFalse(key in self.module._interned_tuples)
 
467
        key2 = self.module.StaticTuple(unique_str1, unique_str2)
 
468
        self.assertEqual(key, key2)
 
469
        self.assertIsNot(key, key2)
 
470
        key3 = key.intern()
 
471
        self.assertIs(key, key3)
 
472
        self.assertTrue(key in self.module._interned_tuples)
 
473
        self.assertEqual(key, self.module._interned_tuples[key])
 
474
        key2 = key2.intern()
 
475
        self.assertIs(key, key2)
 
476
 
 
477
    def test__c_intern_handles_refcount(self):
 
478
        if self.module is _static_tuple_py:
 
479
            return # Not applicable
 
480
        unique_str1 = 'unique str ' + osutils.rand_chars(20)
 
481
        unique_str2 = 'unique str ' + osutils.rand_chars(20)
 
482
        key = self.module.StaticTuple(unique_str1, unique_str2)
 
483
        self.assertRefcount(1, key)
 
484
        self.assertFalse(key in self.module._interned_tuples)
 
485
        self.assertFalse(key._is_interned())
 
486
        key2 = self.module.StaticTuple(unique_str1, unique_str2)
 
487
        self.assertRefcount(1, key)
 
488
        self.assertRefcount(1, key2)
 
489
        self.assertEqual(key, key2)
 
490
        self.assertIsNot(key, key2)
 
491
 
 
492
        key3 = key.intern()
 
493
        self.assertIs(key, key3)
 
494
        self.assertTrue(key in self.module._interned_tuples)
 
495
        self.assertEqual(key, self.module._interned_tuples[key])
 
496
        # key and key3, but we 'hide' the one in _interned_tuples
 
497
        self.assertRefcount(2, key)
 
498
        del key3
 
499
        self.assertRefcount(1, key)
 
500
        self.assertTrue(key._is_interned())
 
501
        self.assertRefcount(1, key2)
 
502
        key3 = key2.intern()
 
503
        # key3 now points to key as well, and *not* to key2
 
504
        self.assertRefcount(2, key)
 
505
        self.assertRefcount(1, key2)
 
506
        self.assertIs(key, key3)
 
507
        self.assertIsNot(key3, key2)
 
508
        del key2
 
509
        del key3
 
510
        self.assertRefcount(1, key)
 
511
 
 
512
    def test__c_keys_are_not_immortal(self):
 
513
        if self.module is _static_tuple_py:
 
514
            return # Not applicable
 
515
        unique_str1 = 'unique str ' + osutils.rand_chars(20)
 
516
        unique_str2 = 'unique str ' + osutils.rand_chars(20)
 
517
        key = self.module.StaticTuple(unique_str1, unique_str2)
 
518
        self.assertFalse(key in self.module._interned_tuples)
 
519
        self.assertRefcount(1, key)
 
520
        key = key.intern()
 
521
        self.assertRefcount(1, key)
 
522
        self.assertTrue(key in self.module._interned_tuples)
 
523
        self.assertTrue(key._is_interned())
 
524
        del key
 
525
        # Create a new entry, which would point to the same location
 
526
        key = self.module.StaticTuple(unique_str1, unique_str2)
 
527
        self.assertRefcount(1, key)
 
528
        # This old entry in _interned_tuples should be gone
 
529
        self.assertFalse(key in self.module._interned_tuples)
 
530
        self.assertFalse(key._is_interned())
 
531
 
 
532
    def test__c_has_C_API(self):
 
533
        if self.module is _static_tuple_py:
 
534
            return
 
535
        self.assertIsNot(None, self.module._C_API)
 
536
 
 
537
    def test_from_sequence_tuple(self):
 
538
        st = self.module.StaticTuple.from_sequence(('foo', 'bar'))
 
539
        self.assertIsInstance(st, self.module.StaticTuple)
 
540
        self.assertEqual(('foo', 'bar'), st)
 
541
 
 
542
    def test_from_sequence_str(self):
 
543
        st = self.module.StaticTuple.from_sequence('foo')
 
544
        self.assertIsInstance(st, self.module.StaticTuple)
 
545
        self.assertEqual(('f', 'o', 'o'), st)
 
546
 
 
547
    def test_from_sequence_list(self):
 
548
        st = self.module.StaticTuple.from_sequence(['foo', 'bar'])
 
549
        self.assertIsInstance(st, self.module.StaticTuple)
 
550
        self.assertEqual(('foo', 'bar'), st)
 
551
 
 
552
    def test_from_sequence_static_tuple(self):
 
553
        st = self.module.StaticTuple('foo', 'bar')
 
554
        st2 = self.module.StaticTuple.from_sequence(st)
 
555
        # If the source is a StaticTuple already, we return the exact object
 
556
        self.assertIs(st, st2)
 
557
 
 
558
    def test_from_sequence_not_sequence(self):
 
559
        self.assertRaises(TypeError,
 
560
                          self.module.StaticTuple.from_sequence, object())
 
561
        self.assertRaises(TypeError,
 
562
                          self.module.StaticTuple.from_sequence, 10)
 
563
 
 
564
    def test_from_sequence_incorrect_args(self):
 
565
        self.assertRaises(TypeError,
 
566
                          self.module.StaticTuple.from_sequence, object(), 'a')
 
567
        self.assertRaises(TypeError,
 
568
                          self.module.StaticTuple.from_sequence, foo='a')
 
569
 
 
570
    def test_from_sequence_iterable(self):
 
571
        st = self.module.StaticTuple.from_sequence(iter(['foo', 'bar']))
 
572
        self.assertIsInstance(st, self.module.StaticTuple)
 
573
        self.assertEqual(('foo', 'bar'), st)
 
574
 
 
575
    def test_from_sequence_generator(self):
 
576
        def generate_tuple():
 
577
            yield 'foo'
 
578
            yield 'bar'
 
579
        st = self.module.StaticTuple.from_sequence(generate_tuple())
 
580
        self.assertIsInstance(st, self.module.StaticTuple)
 
581
        self.assertEqual(('foo', 'bar'), st)
 
582
 
 
583
    def test_pickle(self):
 
584
        st = self.module.StaticTuple('foo', 'bar')
 
585
        pickled = cPickle.dumps(st)
 
586
        unpickled = cPickle.loads(pickled)
 
587
        self.assertEqual(unpickled, st)
 
588
 
 
589
    def test_pickle_empty(self):
 
590
        st = self.module.StaticTuple()
 
591
        pickled = cPickle.dumps(st)
 
592
        unpickled = cPickle.loads(pickled)
 
593
        self.assertIs(st, unpickled)
 
594
 
 
595
    def test_pickle_nested(self):
 
596
        st = self.module.StaticTuple('foo', self.module.StaticTuple('bar'))
 
597
        pickled = cPickle.dumps(st)
 
598
        unpickled = cPickle.loads(pickled)
 
599
        self.assertEqual(unpickled, st)
 
600
 
 
601
    def test_static_tuple_thunk(self):
 
602
        # Make sure the right implementation is available from
 
603
        # bzrlib.static_tuple.StaticTuple.
 
604
        if self.module is _static_tuple_py:
 
605
            if compiled_static_tuple_feature.available():
 
606
                # We will be using the C version
 
607
                return
 
608
        self.assertIs(static_tuple.StaticTuple,
 
609
                      self.module.StaticTuple)
 
610
 
 
611
 
 
612
class TestEnsureStaticTuple(tests.TestCase):
 
613
 
 
614
    def test_is_static_tuple(self):
 
615
        st = static_tuple.StaticTuple('foo')
 
616
        st2 = static_tuple.expect_static_tuple(st)
 
617
        self.assertIs(st, st2)
 
618
 
 
619
    def test_is_tuple(self):
 
620
        t = ('foo',)
 
621
        st = static_tuple.expect_static_tuple(t)
 
622
        self.assertIsInstance(st, static_tuple.StaticTuple)
 
623
        self.assertEqual(t, st)
 
624
 
 
625
    def test_flagged_is_static_tuple(self):
 
626
        debug.debug_flags.add('static_tuple')
 
627
        st = static_tuple.StaticTuple('foo')
 
628
        st2 = static_tuple.expect_static_tuple(st)
 
629
        self.assertIs(st, st2)
 
630
 
 
631
    def test_flagged_is_tuple(self):
 
632
        debug.debug_flags.add('static_tuple')
 
633
        t = ('foo',)
 
634
        self.assertRaises(TypeError, static_tuple.expect_static_tuple, t)