1
# Copyright (C) 2007, 2008 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 compiled dirstate helpers."""
29
from bzrlib.tests import (
32
from bzrlib.tests import test_dirstate
35
class _CompiledDirstateHelpersFeature(tests.Feature):
38
import bzrlib._dirstate_helpers_c
43
def feature_name(self):
44
return 'bzrlib._dirstate_helpers_c'
46
CompiledDirstateHelpersFeature = _CompiledDirstateHelpersFeature()
49
class TestBisectPathMixin(object):
50
"""Test that _bisect_path_*() returns the expected values.
52
_bisect_path_* is intended to work like bisect.bisect_*() except it
53
knows it is working on paths that are sorted by ('path', 'to', 'foo')
54
chunks rather than by raw 'path/to/foo'.
56
Test Cases should inherit from this and override ``get_bisect_path`` return
57
their implementation, and ``get_bisect`` to return the matching
58
bisect.bisect_* function.
61
def get_bisect_path(self):
62
"""Return an implementation of _bisect_path_*"""
63
raise NotImplementedError
66
"""Return a version of bisect.bisect_*.
68
Also, for the 'exists' check, return the offset to the real values.
69
For example bisect_left returns the index of an entry, while
70
bisect_right returns the index *after* an entry
72
:return: (bisect_func, offset)
74
raise NotImplementedError
76
def assertBisect(self, paths, split_paths, path, exists=True):
77
"""Assert that bisect_split works like bisect_left on the split paths.
79
:param paths: A list of path names
80
:param split_paths: A list of path names that are already split up by directory
81
('path/to/foo' => ('path', 'to', 'foo'))
82
:param path: The path we are indexing.
83
:param exists: The path should be present, so make sure the
84
final location actually points to the right value.
86
All other arguments will be passed along.
88
bisect_path = self.get_bisect_path()
89
self.assertIsInstance(paths, list)
90
bisect_path_idx = bisect_path(paths, path)
91
split_path = self.split_for_dirblocks([path])[0]
92
bisect_func, offset = self.get_bisect()
93
bisect_split_idx = bisect_func(split_paths, split_path)
94
self.assertEqual(bisect_split_idx, bisect_path_idx,
95
'%s disagreed. %s != %s'
97
% (bisect_path.__name__,
98
bisect_split_idx, bisect_path_idx, path)
101
self.assertEqual(path, paths[bisect_path_idx+offset])
103
def split_for_dirblocks(self, paths):
106
dirname, basename = os.path.split(path)
107
dir_split_paths.append((dirname.split('/'), basename))
108
dir_split_paths.sort()
109
return dir_split_paths
111
def test_simple(self):
112
"""In the simple case it works just like bisect_left"""
113
paths = ['', 'a', 'b', 'c', 'd']
114
split_paths = self.split_for_dirblocks(paths)
116
self.assertBisect(paths, split_paths, path, exists=True)
117
self.assertBisect(paths, split_paths, '_', exists=False)
118
self.assertBisect(paths, split_paths, 'aa', exists=False)
119
self.assertBisect(paths, split_paths, 'bb', exists=False)
120
self.assertBisect(paths, split_paths, 'cc', exists=False)
121
self.assertBisect(paths, split_paths, 'dd', exists=False)
122
self.assertBisect(paths, split_paths, 'a/a', exists=False)
123
self.assertBisect(paths, split_paths, 'b/b', exists=False)
124
self.assertBisect(paths, split_paths, 'c/c', exists=False)
125
self.assertBisect(paths, split_paths, 'd/d', exists=False)
127
def test_involved(self):
128
"""This is where bisect_path_* diverges slightly."""
129
# This is the list of paths and their contents
157
# This is the exact order that is stored by dirstate
158
# All children in a directory are mentioned before an children of
159
# children are mentioned.
160
# So all the root-directory paths, then all the
161
# first sub directory, etc.
162
paths = [# content of '/'
163
'', 'a', 'a-a', 'a-z', 'a=a', 'a=z',
165
'a/a', 'a/a-a', 'a/a-z',
167
'a/z', 'a/z-a', 'a/z-z',
190
split_paths = self.split_for_dirblocks(paths)
192
for dir_parts, basename in split_paths:
193
if dir_parts == ['']:
194
sorted_paths.append(basename)
196
sorted_paths.append('/'.join(dir_parts + [basename]))
198
self.assertEqual(sorted_paths, paths)
201
self.assertBisect(paths, split_paths, path, exists=True)
204
class TestBisectPathLeft(tests.TestCase, TestBisectPathMixin):
205
"""Run all Bisect Path tests against _bisect_path_left_py."""
207
def get_bisect_path(self):
208
from bzrlib._dirstate_helpers_py import _bisect_path_left_py
209
return _bisect_path_left_py
211
def get_bisect(self):
212
return bisect.bisect_left, 0
215
class TestCompiledBisectPathLeft(TestBisectPathLeft):
216
"""Run all Bisect Path tests against _bisect_path_right_c"""
218
_test_needs_features = [CompiledDirstateHelpersFeature]
220
def get_bisect_path(self):
221
from bzrlib._dirstate_helpers_c import _bisect_path_left_c
222
return _bisect_path_left_c
225
class TestBisectPathRight(tests.TestCase, TestBisectPathMixin):
226
"""Run all Bisect Path tests against _bisect_path_right_py"""
228
def get_bisect_path(self):
229
from bzrlib._dirstate_helpers_py import _bisect_path_right_py
230
return _bisect_path_right_py
232
def get_bisect(self):
233
return bisect.bisect_right, -1
236
class TestCompiledBisectPathRight(TestBisectPathRight):
237
"""Run all Bisect Path tests against _bisect_path_right_c"""
239
_test_needs_features = [CompiledDirstateHelpersFeature]
241
def get_bisect_path(self):
242
from bzrlib._dirstate_helpers_c import _bisect_path_right_c
243
return _bisect_path_right_c
246
class TestBisectDirblock(tests.TestCase):
247
"""Test that bisect_dirblock() returns the expected values.
249
bisect_dirblock is intended to work like bisect.bisect_left() except it
250
knows it is working on dirblocks and that dirblocks are sorted by ('path',
251
'to', 'foo') chunks rather than by raw 'path/to/foo'.
253
This test is parameterized by calling get_bisect_dirblock(). Child test
254
cases can override this function to test against a different
258
def get_bisect_dirblock(self):
259
"""Return an implementation of bisect_dirblock"""
260
from bzrlib._dirstate_helpers_py import bisect_dirblock_py
261
return bisect_dirblock_py
263
def assertBisect(self, dirblocks, split_dirblocks, path, *args, **kwargs):
264
"""Assert that bisect_split works like bisect_left on the split paths.
266
:param dirblocks: A list of (path, [info]) pairs.
267
:param split_dirblocks: A list of ((split, path), [info]) pairs.
268
:param path: The path we are indexing.
270
All other arguments will be passed along.
272
bisect_dirblock = self.get_bisect_dirblock()
273
self.assertIsInstance(dirblocks, list)
274
bisect_split_idx = bisect_dirblock(dirblocks, path, *args, **kwargs)
275
split_dirblock = (path.split('/'), [])
276
bisect_left_idx = bisect.bisect_left(split_dirblocks, split_dirblock,
278
self.assertEqual(bisect_left_idx, bisect_split_idx,
279
'bisect_split disagreed. %s != %s'
281
% (bisect_left_idx, bisect_split_idx, path)
284
def paths_to_dirblocks(self, paths):
285
"""Convert a list of paths into dirblock form.
287
Also, ensure that the paths are in proper sorted order.
289
dirblocks = [(path, []) for path in paths]
290
split_dirblocks = [(path.split('/'), []) for path in paths]
291
self.assertEqual(sorted(split_dirblocks), split_dirblocks)
292
return dirblocks, split_dirblocks
294
def test_simple(self):
295
"""In the simple case it works just like bisect_left"""
296
paths = ['', 'a', 'b', 'c', 'd']
297
dirblocks, split_dirblocks = self.paths_to_dirblocks(paths)
299
self.assertBisect(dirblocks, split_dirblocks, path)
300
self.assertBisect(dirblocks, split_dirblocks, '_')
301
self.assertBisect(dirblocks, split_dirblocks, 'aa')
302
self.assertBisect(dirblocks, split_dirblocks, 'bb')
303
self.assertBisect(dirblocks, split_dirblocks, 'cc')
304
self.assertBisect(dirblocks, split_dirblocks, 'dd')
305
self.assertBisect(dirblocks, split_dirblocks, 'a/a')
306
self.assertBisect(dirblocks, split_dirblocks, 'b/b')
307
self.assertBisect(dirblocks, split_dirblocks, 'c/c')
308
self.assertBisect(dirblocks, split_dirblocks, 'd/d')
310
def test_involved(self):
311
"""This is where bisect_left diverges slightly."""
313
'a/a', 'a/a/a', 'a/a/z', 'a/a-a', 'a/a-z',
314
'a/z', 'a/z/a', 'a/z/z', 'a/z-a', 'a/z-z',
316
'z', 'z/a/a', 'z/a/z', 'z/a-a', 'z/a-z',
317
'z/z', 'z/z/a', 'z/z/z', 'z/z-a', 'z/z-z',
320
dirblocks, split_dirblocks = self.paths_to_dirblocks(paths)
322
self.assertBisect(dirblocks, split_dirblocks, path)
324
def test_involved_cached(self):
325
"""This is where bisect_left diverges slightly."""
327
'a/a', 'a/a/a', 'a/a/z', 'a/a-a', 'a/a-z',
328
'a/z', 'a/z/a', 'a/z/z', 'a/z-a', 'a/z-z',
330
'z', 'z/a/a', 'z/a/z', 'z/a-a', 'z/a-z',
331
'z/z', 'z/z/a', 'z/z/z', 'z/z-a', 'z/z-z',
335
dirblocks, split_dirblocks = self.paths_to_dirblocks(paths)
337
self.assertBisect(dirblocks, split_dirblocks, path, cache=cache)
340
class TestCompiledBisectDirblock(TestBisectDirblock):
341
"""Test that bisect_dirblock() returns the expected values.
343
bisect_dirblock is intended to work like bisect.bisect_left() except it
344
knows it is working on dirblocks and that dirblocks are sorted by ('path',
345
'to', 'foo') chunks rather than by raw 'path/to/foo'.
347
This runs all the normal tests that TestBisectDirblock did, but uses the
351
_test_needs_features = [CompiledDirstateHelpersFeature]
353
def get_bisect_dirblock(self):
354
from bzrlib._dirstate_helpers_c import bisect_dirblock_c
355
return bisect_dirblock_c
358
class TestCmpByDirs(tests.TestCase):
359
"""Test an implementation of cmp_by_dirs()
361
cmp_by_dirs() compares 2 paths by their directory sections, rather than as
364
Child test cases can override ``get_cmp_by_dirs`` to test a specific
368
def get_cmp_by_dirs(self):
369
"""Get a specific implementation of cmp_by_dirs."""
370
from bzrlib._dirstate_helpers_py import cmp_by_dirs_py
371
return cmp_by_dirs_py
373
def assertCmpByDirs(self, expected, str1, str2):
374
"""Compare the two strings, in both directions.
376
:param expected: The expected comparison value. -1 means str1 comes
377
first, 0 means they are equal, 1 means str2 comes first
378
:param str1: string to compare
379
:param str2: string to compare
381
cmp_by_dirs = self.get_cmp_by_dirs()
383
self.assertEqual(str1, str2)
384
self.assertEqual(0, cmp_by_dirs(str1, str2))
385
self.assertEqual(0, cmp_by_dirs(str2, str1))
387
self.assertPositive(cmp_by_dirs(str1, str2))
388
self.assertNegative(cmp_by_dirs(str2, str1))
390
self.assertNegative(cmp_by_dirs(str1, str2))
391
self.assertPositive(cmp_by_dirs(str2, str1))
393
def test_cmp_empty(self):
394
"""Compare against the empty string."""
395
self.assertCmpByDirs(0, '', '')
396
self.assertCmpByDirs(1, 'a', '')
397
self.assertCmpByDirs(1, 'ab', '')
398
self.assertCmpByDirs(1, 'abc', '')
399
self.assertCmpByDirs(1, 'abcd', '')
400
self.assertCmpByDirs(1, 'abcde', '')
401
self.assertCmpByDirs(1, 'abcdef', '')
402
self.assertCmpByDirs(1, 'abcdefg', '')
403
self.assertCmpByDirs(1, 'abcdefgh', '')
404
self.assertCmpByDirs(1, 'abcdefghi', '')
405
self.assertCmpByDirs(1, 'test/ing/a/path/', '')
407
def test_cmp_same_str(self):
408
"""Compare the same string"""
409
self.assertCmpByDirs(0, 'a', 'a')
410
self.assertCmpByDirs(0, 'ab', 'ab')
411
self.assertCmpByDirs(0, 'abc', 'abc')
412
self.assertCmpByDirs(0, 'abcd', 'abcd')
413
self.assertCmpByDirs(0, 'abcde', 'abcde')
414
self.assertCmpByDirs(0, 'abcdef', 'abcdef')
415
self.assertCmpByDirs(0, 'abcdefg', 'abcdefg')
416
self.assertCmpByDirs(0, 'abcdefgh', 'abcdefgh')
417
self.assertCmpByDirs(0, 'abcdefghi', 'abcdefghi')
418
self.assertCmpByDirs(0, 'testing a long string', 'testing a long string')
419
self.assertCmpByDirs(0, 'x'*10000, 'x'*10000)
420
self.assertCmpByDirs(0, 'a/b', 'a/b')
421
self.assertCmpByDirs(0, 'a/b/c', 'a/b/c')
422
self.assertCmpByDirs(0, 'a/b/c/d', 'a/b/c/d')
423
self.assertCmpByDirs(0, 'a/b/c/d/e', 'a/b/c/d/e')
425
def test_simple_paths(self):
426
"""Compare strings that act like normal string comparison"""
427
self.assertCmpByDirs(-1, 'a', 'b')
428
self.assertCmpByDirs(-1, 'aa', 'ab')
429
self.assertCmpByDirs(-1, 'ab', 'bb')
430
self.assertCmpByDirs(-1, 'aaa', 'aab')
431
self.assertCmpByDirs(-1, 'aab', 'abb')
432
self.assertCmpByDirs(-1, 'abb', 'bbb')
433
self.assertCmpByDirs(-1, 'aaaa', 'aaab')
434
self.assertCmpByDirs(-1, 'aaab', 'aabb')
435
self.assertCmpByDirs(-1, 'aabb', 'abbb')
436
self.assertCmpByDirs(-1, 'abbb', 'bbbb')
437
self.assertCmpByDirs(-1, 'aaaaa', 'aaaab')
438
self.assertCmpByDirs(-1, 'a/a', 'a/b')
439
self.assertCmpByDirs(-1, 'a/b', 'b/b')
440
self.assertCmpByDirs(-1, 'a/a/a', 'a/a/b')
441
self.assertCmpByDirs(-1, 'a/a/b', 'a/b/b')
442
self.assertCmpByDirs(-1, 'a/b/b', 'b/b/b')
443
self.assertCmpByDirs(-1, 'a/a/a/a', 'a/a/a/b')
444
self.assertCmpByDirs(-1, 'a/a/a/b', 'a/a/b/b')
445
self.assertCmpByDirs(-1, 'a/a/b/b', 'a/b/b/b')
446
self.assertCmpByDirs(-1, 'a/b/b/b', 'b/b/b/b')
447
self.assertCmpByDirs(-1, 'a/a/a/a/a', 'a/a/a/a/b')
449
def test_tricky_paths(self):
450
self.assertCmpByDirs(1, 'ab/cd/ef', 'ab/cc/ef')
451
self.assertCmpByDirs(1, 'ab/cd/ef', 'ab/c/ef')
452
self.assertCmpByDirs(-1, 'ab/cd/ef', 'ab/cd-ef')
453
self.assertCmpByDirs(-1, 'ab/cd', 'ab/cd-')
454
self.assertCmpByDirs(-1, 'ab/cd', 'ab-cd')
456
def test_cmp_unicode_not_allowed(self):
457
cmp_by_dirs = self.get_cmp_by_dirs()
458
self.assertRaises(TypeError, cmp_by_dirs, u'Unicode', 'str')
459
self.assertRaises(TypeError, cmp_by_dirs, 'str', u'Unicode')
460
self.assertRaises(TypeError, cmp_by_dirs, u'Unicode', u'Unicode')
462
def test_cmp_non_ascii(self):
463
self.assertCmpByDirs(-1, '\xc2\xb5', '\xc3\xa5') # u'\xb5', u'\xe5'
464
self.assertCmpByDirs(-1, 'a', '\xc3\xa5') # u'a', u'\xe5'
465
self.assertCmpByDirs(-1, 'b', '\xc2\xb5') # u'b', u'\xb5'
466
self.assertCmpByDirs(-1, 'a/b', 'a/\xc3\xa5') # u'a/b', u'a/\xe5'
467
self.assertCmpByDirs(-1, 'b/a', 'b/\xc2\xb5') # u'b/a', u'b/\xb5'
470
class TestCompiledCmpByDirs(TestCmpByDirs):
471
"""Test the pyrex implementation of cmp_by_dirs"""
473
_test_needs_features = [CompiledDirstateHelpersFeature]
475
def get_cmp_by_dirs(self):
476
from bzrlib._dirstate_helpers_c import cmp_by_dirs_c
480
class TestCmpPathByDirblock(tests.TestCase):
481
"""Test an implementation of _cmp_path_by_dirblock()
483
_cmp_path_by_dirblock() compares two paths using the sort order used by
484
DirState. All paths in the same directory are sorted together.
486
Child test cases can override ``get_cmp_path_by_dirblock`` to test a specific
490
def get_cmp_path_by_dirblock(self):
491
"""Get a specific implementation of _cmp_path_by_dirblock."""
492
from bzrlib._dirstate_helpers_py import _cmp_path_by_dirblock_py
493
return _cmp_path_by_dirblock_py
495
def assertCmpPathByDirblock(self, paths):
496
"""Compare all paths and make sure they evaluate to the correct order.
498
This does N^2 comparisons. It is assumed that ``paths`` is properly
501
:param paths: a sorted list of paths to compare
503
# First, make sure the paths being passed in are correct
505
dirname, basename = os.path.split(p)
506
return dirname.split('/'), basename
507
self.assertEqual(sorted(paths, key=_key), paths)
509
cmp_path_by_dirblock = self.get_cmp_path_by_dirblock()
510
for idx1, path1 in enumerate(paths):
511
for idx2, path2 in enumerate(paths):
512
cmp_val = cmp_path_by_dirblock(path1, path2)
514
self.assertTrue(cmp_val < 0,
515
'%s did not state that %r came before %r, cmp=%s'
516
% (cmp_path_by_dirblock.__name__,
517
path1, path2, cmp_val))
519
self.assertTrue(cmp_val > 0,
520
'%s did not state that %r came after %r, cmp=%s'
521
% (cmp_path_by_dirblock.__name__,
522
path1, path2, cmp_val))
524
self.assertTrue(cmp_val == 0,
525
'%s did not state that %r == %r, cmp=%s'
526
% (cmp_path_by_dirblock.__name__,
527
path1, path2, cmp_val))
529
def test_cmp_simple_paths(self):
530
"""Compare against the empty string."""
531
self.assertCmpPathByDirblock(['', 'a', 'ab', 'abc', 'a/b/c', 'b/d/e'])
532
self.assertCmpPathByDirblock(['kl', 'ab/cd', 'ab/ef', 'gh/ij'])
534
def test_tricky_paths(self):
535
self.assertCmpPathByDirblock([
537
'', 'a', 'a-a', 'a=a', 'b',
539
'a/a', 'a/a-a', 'a/a=a', 'a/b',
541
'a/a/a', 'a/a/a-a', 'a/a/a=a',
542
# Contents of 'a/a/a'
543
'a/a/a/a', 'a/a/a/b',
544
# Contents of 'a/a/a-a',
545
'a/a/a-a/a', 'a/a/a-a/b',
546
# Contents of 'a/a/a=a',
547
'a/a/a=a/a', 'a/a/a=a/b',
548
# Contents of 'a/a-a'
550
# Contents of 'a/a-a/a'
551
'a/a-a/a/a', 'a/a-a/a/b',
552
# Contents of 'a/a=a'
563
self.assertCmpPathByDirblock([
565
'', 'a', 'a-a', 'a-z', 'a=a', 'a=z',
567
'a/a', 'a/a-a', 'a/a-z',
569
'a/z', 'a/z-a', 'a/z-z',
593
def test_unicode_not_allowed(self):
594
cmp_path_by_dirblock = self.get_cmp_path_by_dirblock()
595
self.assertRaises(TypeError, cmp_path_by_dirblock, u'Uni', 'str')
596
self.assertRaises(TypeError, cmp_path_by_dirblock, 'str', u'Uni')
597
self.assertRaises(TypeError, cmp_path_by_dirblock, u'Uni', u'Uni')
598
self.assertRaises(TypeError, cmp_path_by_dirblock, u'x/Uni', 'x/str')
599
self.assertRaises(TypeError, cmp_path_by_dirblock, 'x/str', u'x/Uni')
600
self.assertRaises(TypeError, cmp_path_by_dirblock, u'x/Uni', u'x/Uni')
602
def test_nonascii(self):
603
self.assertCmpPathByDirblock([
605
'', 'a', '\xc2\xb5', '\xc3\xa5',
607
'a/a', 'a/\xc2\xb5', 'a/\xc3\xa5',
609
'a/a/a', 'a/a/\xc2\xb5', 'a/a/\xc3\xa5',
610
# content of 'a/\xc2\xb5'
611
'a/\xc2\xb5/a', 'a/\xc2\xb5/\xc2\xb5', 'a/\xc2\xb5/\xc3\xa5',
612
# content of 'a/\xc3\xa5'
613
'a/\xc3\xa5/a', 'a/\xc3\xa5/\xc2\xb5', 'a/\xc3\xa5/\xc3\xa5',
614
# content of '\xc2\xb5'
615
'\xc2\xb5/a', '\xc2\xb5/\xc2\xb5', '\xc2\xb5/\xc3\xa5',
616
# content of '\xc2\xe5'
617
'\xc3\xa5/a', '\xc3\xa5/\xc2\xb5', '\xc3\xa5/\xc3\xa5',
621
class TestCompiledCmpPathByDirblock(TestCmpPathByDirblock):
622
"""Test the pyrex implementation of _cmp_path_by_dirblock"""
624
_test_needs_features = [CompiledDirstateHelpersFeature]
626
def get_cmp_by_dirs(self):
627
from bzrlib._dirstate_helpers_c import _cmp_path_by_dirblock_c
628
return _cmp_path_by_dirblock_c
631
class TestMemRChr(tests.TestCase):
632
"""Test memrchr functionality"""
634
_test_needs_features = [CompiledDirstateHelpersFeature]
636
def assertMemRChr(self, expected, s, c):
637
from bzrlib._dirstate_helpers_c import _py_memrchr
638
self.assertEqual(expected, _py_memrchr(s, c))
640
def test_missing(self):
641
self.assertMemRChr(None, '', 'a')
642
self.assertMemRChr(None, '', 'c')
643
self.assertMemRChr(None, 'abcdefghijklm', 'q')
644
self.assertMemRChr(None, 'aaaaaaaaaaaaaaaaaaaaaaa', 'b')
646
def test_single_entry(self):
647
self.assertMemRChr(0, 'abcdefghijklm', 'a')
648
self.assertMemRChr(1, 'abcdefghijklm', 'b')
649
self.assertMemRChr(2, 'abcdefghijklm', 'c')
650
self.assertMemRChr(10, 'abcdefghijklm', 'k')
651
self.assertMemRChr(11, 'abcdefghijklm', 'l')
652
self.assertMemRChr(12, 'abcdefghijklm', 'm')
654
def test_multiple(self):
655
self.assertMemRChr(10, 'abcdefjklmabcdefghijklm', 'a')
656
self.assertMemRChr(11, 'abcdefjklmabcdefghijklm', 'b')
657
self.assertMemRChr(12, 'abcdefjklmabcdefghijklm', 'c')
658
self.assertMemRChr(20, 'abcdefjklmabcdefghijklm', 'k')
659
self.assertMemRChr(21, 'abcdefjklmabcdefghijklm', 'l')
660
self.assertMemRChr(22, 'abcdefjklmabcdefghijklm', 'm')
661
self.assertMemRChr(22, 'aaaaaaaaaaaaaaaaaaaaaaa', 'a')
663
def test_with_nulls(self):
664
self.assertMemRChr(10, 'abc\0\0\0jklmabc\0\0\0ghijklm', 'a')
665
self.assertMemRChr(11, 'abc\0\0\0jklmabc\0\0\0ghijklm', 'b')
666
self.assertMemRChr(12, 'abc\0\0\0jklmabc\0\0\0ghijklm', 'c')
667
self.assertMemRChr(20, 'abc\0\0\0jklmabc\0\0\0ghijklm', 'k')
668
self.assertMemRChr(21, 'abc\0\0\0jklmabc\0\0\0ghijklm', 'l')
669
self.assertMemRChr(22, 'abc\0\0\0jklmabc\0\0\0ghijklm', 'm')
670
self.assertMemRChr(22, 'aaa\0\0\0aaaaaaa\0\0\0aaaaaaa', 'a')
671
self.assertMemRChr(9, '\0\0\0\0\0\0\0\0\0\0', '\0')
674
class TestReadDirblocks(test_dirstate.TestCaseWithDirState):
675
"""Test an implementation of _read_dirblocks()
677
_read_dirblocks() reads in all of the dirblock information from the disk
680
Child test cases can override ``get_read_dirblocks`` to test a specific
684
def get_read_dirblocks(self):
685
from bzrlib._dirstate_helpers_py import _read_dirblocks_py
686
return _read_dirblocks_py
688
def test_smoketest(self):
689
"""Make sure that we can create and read back a simple file."""
690
tree, state, expected = self.create_basic_dirstate()
692
state._read_header_if_needed()
693
self.assertEqual(dirstate.DirState.NOT_IN_MEMORY,
694
state._dirblock_state)
695
read_dirblocks = self.get_read_dirblocks()
696
read_dirblocks(state)
697
self.assertEqual(dirstate.DirState.IN_MEMORY_UNMODIFIED,
698
state._dirblock_state)
700
def test_trailing_garbage(self):
701
tree, state, expected = self.create_basic_dirstate()
702
# We can modify the file as long as it hasn't been read yet.
703
f = open('dirstate', 'ab')
705
# Add bogus trailing garbage
709
e = self.assertRaises(errors.DirstateCorrupt,
710
state._read_dirblocks_if_needed)
711
# Make sure we mention the bogus characters in the error
712
self.assertContainsRe(str(e), 'bogus')
715
class TestCompiledReadDirblocks(TestReadDirblocks):
716
"""Test the pyrex implementation of _read_dirblocks"""
718
_test_needs_features = [CompiledDirstateHelpersFeature]
720
def get_read_dirblocks(self):
721
from bzrlib._dirstate_helpers_c import _read_dirblocks_c
722
return _read_dirblocks_c
725
class TestUsingCompiledIfAvailable(tests.TestCase):
726
"""Check that any compiled functions that are available are the default.
728
It is possible to have typos, etc in the import line, such that
729
_dirstate_helpers_c is actually available, but the compiled functions are
733
def test_bisect_dirblock(self):
734
if CompiledDirstateHelpersFeature.available():
735
from bzrlib._dirstate_helpers_c import bisect_dirblock_c
736
self.assertIs(bisect_dirblock_c, dirstate.bisect_dirblock)
738
from bzrlib._dirstate_helpers_py import bisect_dirblock_py
739
self.assertIs(bisect_dirblock_py, dirstate.bisect_dirblock)
741
def test__bisect_path_left(self):
742
if CompiledDirstateHelpersFeature.available():
743
from bzrlib._dirstate_helpers_c import _bisect_path_left_c
744
self.assertIs(_bisect_path_left_c, dirstate._bisect_path_left)
746
from bzrlib._dirstate_helpers_py import _bisect_path_left_py
747
self.assertIs(_bisect_path_left_py, dirstate._bisect_path_left)
749
def test__bisect_path_right(self):
750
if CompiledDirstateHelpersFeature.available():
751
from bzrlib._dirstate_helpers_c import _bisect_path_right_c
752
self.assertIs(_bisect_path_right_c, dirstate._bisect_path_right)
754
from bzrlib._dirstate_helpers_py import _bisect_path_right_py
755
self.assertIs(_bisect_path_right_py, dirstate._bisect_path_right)
757
def test_cmp_by_dirs(self):
758
if CompiledDirstateHelpersFeature.available():
759
from bzrlib._dirstate_helpers_c import cmp_by_dirs_c
760
self.assertIs(cmp_by_dirs_c, dirstate.cmp_by_dirs)
762
from bzrlib._dirstate_helpers_py import cmp_by_dirs_py
763
self.assertIs(cmp_by_dirs_py, dirstate.cmp_by_dirs)
765
def test__read_dirblocks(self):
766
if CompiledDirstateHelpersFeature.available():
767
from bzrlib._dirstate_helpers_c import _read_dirblocks_c
768
self.assertIs(_read_dirblocks_c, dirstate._read_dirblocks)
770
from bzrlib._dirstate_helpers_py import _read_dirblocks_py
771
self.assertIs(_read_dirblocks_py, dirstate._read_dirblocks)
773
def test_update_entry(self):
774
if CompiledDirstateHelpersFeature.available():
775
from bzrlib._dirstate_helpers_c import update_entry
776
self.assertIs(update_entry, dirstate.update_entry)
778
from bzrlib.dirstate import py_update_entry
779
self.assertIs(py_update_entry, dirstate.py_update_entry)
781
def test_process_entry(self):
782
if CompiledDirstateHelpersFeature.available():
783
from bzrlib._dirstate_helpers_c import ProcessEntryC
784
self.assertIs(ProcessEntryC, dirstate._process_entry)
786
from bzrlib.dirstate import ProcessEntryPython
787
self.assertIs(ProcessEntryPython, dirstate._process_entry)
790
class TestUpdateEntry(test_dirstate.TestCaseWithDirState):
791
"""Test the DirState.update_entry functions"""
793
def get_state_with_a(self):
794
"""Create a DirState tracking a single object named 'a'"""
795
state = test_dirstate.InstrumentedDirState.initialize('dirstate')
796
self.addCleanup(state.unlock)
797
state.add('a', 'a-id', 'file', None, '')
798
entry = state._get_entry(0, path_utf8='a')
799
self.set_update_entry()
802
def set_update_entry(self):
803
self.update_entry = dirstate.py_update_entry
805
def test_observed_sha1_cachable(self):
806
state, entry = self.get_state_with_a()
807
atime = time.time() - 10
808
self.build_tree(['a'])
809
statvalue = os.lstat('a')
810
statvalue = test_dirstate._FakeStat(statvalue.st_size, atime, atime,
811
statvalue.st_dev, statvalue.st_ino, statvalue.st_mode)
812
state._observed_sha1(entry, "foo", statvalue)
813
self.assertEqual('foo', entry[1][0][1])
814
packed_stat = dirstate.pack_stat(statvalue)
815
self.assertEqual(packed_stat, entry[1][0][4])
817
def test_observed_sha1_not_cachable(self):
818
state, entry = self.get_state_with_a()
819
oldval = entry[1][0][1]
820
oldstat = entry[1][0][4]
821
self.build_tree(['a'])
822
statvalue = os.lstat('a')
823
state._observed_sha1(entry, "foo", statvalue)
824
self.assertEqual(oldval, entry[1][0][1])
825
self.assertEqual(oldstat, entry[1][0][4])
827
def test_update_entry(self):
828
state, _ = self.get_state_with_a()
829
tree = self.make_branch_and_tree('tree')
831
empty_revid = tree.commit('empty')
832
self.build_tree(['tree/a'])
833
tree.add(['a'], ['a-id'])
834
with_a_id = tree.commit('with_a')
835
self.addCleanup(tree.unlock)
836
state.set_parent_trees(
837
[(empty_revid, tree.branch.repository.revision_tree(empty_revid))],
839
entry = state._get_entry(0, path_utf8='a')
840
self.build_tree(['a'])
841
# Add one where we don't provide the stat or sha already
842
self.assertEqual(('', 'a', 'a-id'), entry[0])
843
self.assertEqual(('f', '', 0, False, dirstate.DirState.NULLSTAT),
845
# Flush the buffers to disk
847
self.assertEqual(dirstate.DirState.IN_MEMORY_UNMODIFIED,
848
state._dirblock_state)
850
stat_value = os.lstat('a')
851
packed_stat = dirstate.pack_stat(stat_value)
852
link_or_sha1 = self.update_entry(state, entry, abspath='a',
853
stat_value=stat_value)
854
self.assertEqual(None, link_or_sha1)
856
# The dirblock entry should not have cached the file's sha1 (too new)
857
self.assertEqual(('f', '', 14, False, dirstate.DirState.NULLSTAT),
859
self.assertEqual(dirstate.DirState.IN_MEMORY_MODIFIED,
860
state._dirblock_state)
861
mode = stat_value.st_mode
862
self.assertEqual([('is_exec', mode, False)], state._log)
865
self.assertEqual(dirstate.DirState.IN_MEMORY_UNMODIFIED,
866
state._dirblock_state)
868
# If we do it again right away, we don't know if the file has changed
869
# so we will re-read the file. Roll the clock back so the file is
870
# guaranteed to look too new.
871
state.adjust_time(-10)
874
link_or_sha1 = self.update_entry(state, entry, abspath='a',
875
stat_value=stat_value)
876
self.assertEqual([('is_exec', mode, False)], state._log)
877
self.assertEqual(None, link_or_sha1)
878
self.assertEqual(dirstate.DirState.IN_MEMORY_MODIFIED,
879
state._dirblock_state)
880
self.assertEqual(('f', '', 14, False, dirstate.DirState.NULLSTAT),
884
# If it is cachable (the clock has moved forward) but new it still
885
# won't calculate the sha or cache it.
886
state.adjust_time(+20)
888
link_or_sha1 = dirstate.update_entry(state, entry, abspath='a',
889
stat_value=stat_value)
890
self.assertEqual(None, link_or_sha1)
891
self.assertEqual([('is_exec', mode, False)], state._log)
892
self.assertEqual(('f', '', 14, False, dirstate.DirState.NULLSTAT),
895
# If the file is no longer new, and the clock has been moved forward
896
# sufficiently, it will cache the sha.
898
state.set_parent_trees(
899
[(with_a_id, tree.branch.repository.revision_tree(with_a_id))],
901
entry = state._get_entry(0, path_utf8='a')
903
link_or_sha1 = self.update_entry(state, entry, abspath='a',
904
stat_value=stat_value)
905
self.assertEqual('b50e5406bb5e153ebbeb20268fcf37c87e1ecfb6',
907
self.assertEqual([('is_exec', mode, False), ('sha1', 'a')],
909
self.assertEqual(('f', link_or_sha1, 14, False, packed_stat),
912
# Subsequent calls will just return the cached value
914
link_or_sha1 = self.update_entry(state, entry, abspath='a',
915
stat_value=stat_value)
916
self.assertEqual('b50e5406bb5e153ebbeb20268fcf37c87e1ecfb6',
918
self.assertEqual([], state._log)
919
self.assertEqual(('f', link_or_sha1, 14, False, packed_stat),
922
def test_update_entry_symlink(self):
923
"""Update entry should read symlinks."""
924
self.requireFeature(SymlinkFeature)
925
state, entry = self.get_state_with_a()
927
self.assertEqual(dirstate.DirState.IN_MEMORY_UNMODIFIED,
928
state._dirblock_state)
929
os.symlink('target', 'a')
931
state.adjust_time(-10) # Make the symlink look new
932
stat_value = os.lstat('a')
933
packed_stat = dirstate.pack_stat(stat_value)
934
link_or_sha1 = self.update_entry(state, entry, abspath='a',
935
stat_value=stat_value)
936
self.assertEqual('target', link_or_sha1)
937
self.assertEqual([('read_link', 'a', '')], state._log)
938
# Dirblock is not updated (the link is too new)
939
self.assertEqual([('l', '', 6, False, dirstate.DirState.NULLSTAT)],
941
self.assertEqual(dirstate.DirState.IN_MEMORY_MODIFIED,
942
state._dirblock_state)
944
# Because the stat_value looks new, we should re-read the target
945
link_or_sha1 = self.update_entry(state, entry, abspath='a',
946
stat_value=stat_value)
947
self.assertEqual('target', link_or_sha1)
948
self.assertEqual([('read_link', 'a', ''),
949
('read_link', 'a', ''),
951
self.assertEqual([('l', '', 6, False, dirstate.DirState.NULLSTAT)],
953
state.adjust_time(+20) # Skip into the future, all files look old
954
link_or_sha1 = self.update_entry(state, entry, abspath='a',
955
stat_value=stat_value)
956
self.assertEqual('target', link_or_sha1)
957
# We need to re-read the link because only now can we cache it
958
self.assertEqual([('read_link', 'a', ''),
959
('read_link', 'a', ''),
960
('read_link', 'a', ''),
962
self.assertEqual([('l', 'target', 6, False, packed_stat)],
965
# Another call won't re-read the link
966
self.assertEqual([('read_link', 'a', ''),
967
('read_link', 'a', ''),
968
('read_link', 'a', ''),
970
link_or_sha1 = self.update_entry(state, entry, abspath='a',
971
stat_value=stat_value)
972
self.assertEqual('target', link_or_sha1)
973
self.assertEqual([('l', 'target', 6, False, packed_stat)],
976
def do_update_entry(self, state, entry, abspath):
977
stat_value = os.lstat(abspath)
978
return self.update_entry(state, entry, abspath, stat_value)
980
def test_update_entry_dir(self):
981
state, entry = self.get_state_with_a()
982
self.build_tree(['a/'])
983
self.assertIs(None, self.do_update_entry(state, entry, 'a'))
985
def test_update_entry_dir_unchanged(self):
986
state, entry = self.get_state_with_a()
987
self.build_tree(['a/'])
988
state.adjust_time(+20)
989
self.assertIs(None, self.do_update_entry(state, entry, 'a'))
990
self.assertEqual(dirstate.DirState.IN_MEMORY_MODIFIED,
991
state._dirblock_state)
993
self.assertEqual(dirstate.DirState.IN_MEMORY_UNMODIFIED,
994
state._dirblock_state)
995
self.assertIs(None, self.do_update_entry(state, entry, 'a'))
996
self.assertEqual(dirstate.DirState.IN_MEMORY_UNMODIFIED,
997
state._dirblock_state)
999
def test_update_entry_file_unchanged(self):
1000
state, _ = self.get_state_with_a()
1001
tree = self.make_branch_and_tree('tree')
1003
self.build_tree(['tree/a'])
1004
tree.add(['a'], ['a-id'])
1005
with_a_id = tree.commit('witha')
1006
self.addCleanup(tree.unlock)
1007
state.set_parent_trees(
1008
[(with_a_id, tree.branch.repository.revision_tree(with_a_id))],
1010
entry = state._get_entry(0, path_utf8='a')
1011
self.build_tree(['a'])
1012
sha1sum = 'b50e5406bb5e153ebbeb20268fcf37c87e1ecfb6'
1013
state.adjust_time(+20)
1014
self.assertEqual(sha1sum, self.do_update_entry(state, entry, 'a'))
1015
self.assertEqual(dirstate.DirState.IN_MEMORY_MODIFIED,
1016
state._dirblock_state)
1018
self.assertEqual(dirstate.DirState.IN_MEMORY_UNMODIFIED,
1019
state._dirblock_state)
1020
self.assertEqual(sha1sum, self.do_update_entry(state, entry, 'a'))
1021
self.assertEqual(dirstate.DirState.IN_MEMORY_UNMODIFIED,
1022
state._dirblock_state)
1024
def test_update_entry_tree_reference(self):
1025
self.set_update_entry()
1026
state = test_dirstate.InstrumentedDirState.initialize('dirstate')
1027
self.addCleanup(state.unlock)
1028
state.add('r', 'r-id', 'tree-reference', None, '')
1029
self.build_tree(['r/'])
1030
entry = state._get_entry(0, path_utf8='r')
1031
self.do_update_entry(state, entry, 'r')
1032
entry = state._get_entry(0, path_utf8='r')
1033
self.assertEqual('t', entry[1][0][0])
1035
def create_and_test_file(self, state, entry):
1036
"""Create a file at 'a' and verify the state finds it during update.
1038
The state should already be versioning *something* at 'a'. This makes
1039
sure that state.update_entry recognizes it as a file.
1041
self.build_tree(['a'])
1042
stat_value = os.lstat('a')
1043
packed_stat = dirstate.pack_stat(stat_value)
1045
link_or_sha1 = self.do_update_entry(state, entry, abspath='a')
1046
self.assertEqual(None, link_or_sha1)
1047
self.assertEqual([('f', '', 14, False, dirstate.DirState.NULLSTAT)],
1051
def create_and_test_dir(self, state, entry):
1052
"""Create a directory at 'a' and verify the state finds it.
1054
The state should already be versioning *something* at 'a'. This makes
1055
sure that state.update_entry recognizes it as a directory.
1057
self.build_tree(['a/'])
1058
stat_value = os.lstat('a')
1059
packed_stat = dirstate.pack_stat(stat_value)
1061
link_or_sha1 = self.do_update_entry(state, entry, abspath='a')
1062
self.assertIs(None, link_or_sha1)
1063
self.assertEqual([('d', '', 0, False, packed_stat)], entry[1])
1067
def create_and_test_symlink(self, state, entry):
1068
"""Create a symlink at 'a' and verify the state finds it.
1070
The state should already be versioning *something* at 'a'. This makes
1071
sure that state.update_entry recognizes it as a symlink.
1073
This should not be called if this platform does not have symlink
1076
# caller should care about skipping test on platforms without symlinks
1077
os.symlink('path/to/foo', 'a')
1079
stat_value = os.lstat('a')
1080
packed_stat = dirstate.pack_stat(stat_value)
1082
link_or_sha1 = self.do_update_entry(state, entry, abspath='a')
1083
self.assertEqual('path/to/foo', link_or_sha1)
1084
self.assertEqual([('l', 'path/to/foo', 11, False, packed_stat)],
1088
def test_update_file_to_dir(self):
1089
"""If a file changes to a directory we return None for the sha.
1090
We also update the inventory record.
1092
state, entry = self.get_state_with_a()
1093
# The file sha1 won't be cached unless the file is old
1094
state.adjust_time(+10)
1095
self.create_and_test_file(state, entry)
1097
self.create_and_test_dir(state, entry)
1099
def test_update_file_to_symlink(self):
1100
"""File becomes a symlink"""
1101
self.requireFeature(SymlinkFeature)
1102
state, entry = self.get_state_with_a()
1103
# The file sha1 won't be cached unless the file is old
1104
state.adjust_time(+10)
1105
self.create_and_test_file(state, entry)
1107
self.create_and_test_symlink(state, entry)
1109
def test_update_dir_to_file(self):
1110
"""Directory becoming a file updates the entry."""
1111
state, entry = self.get_state_with_a()
1112
# The file sha1 won't be cached unless the file is old
1113
state.adjust_time(+10)
1114
self.create_and_test_dir(state, entry)
1116
self.create_and_test_file(state, entry)
1118
def test_update_dir_to_symlink(self):
1119
"""Directory becomes a symlink"""
1120
self.requireFeature(SymlinkFeature)
1121
state, entry = self.get_state_with_a()
1122
# The symlink target won't be cached if it isn't old
1123
state.adjust_time(+10)
1124
self.create_and_test_dir(state, entry)
1126
self.create_and_test_symlink(state, entry)
1128
def test_update_symlink_to_file(self):
1129
"""Symlink becomes a file"""
1130
self.requireFeature(SymlinkFeature)
1131
state, entry = self.get_state_with_a()
1132
# The symlink and file info won't be cached unless old
1133
state.adjust_time(+10)
1134
self.create_and_test_symlink(state, entry)
1136
self.create_and_test_file(state, entry)
1138
def test_update_symlink_to_dir(self):
1139
"""Symlink becomes a directory"""
1140
self.requireFeature(SymlinkFeature)
1141
state, entry = self.get_state_with_a()
1142
# The symlink target won't be cached if it isn't old
1143
state.adjust_time(+10)
1144
self.create_and_test_symlink(state, entry)
1146
self.create_and_test_dir(state, entry)
1148
def test__is_executable_win32(self):
1149
state, entry = self.get_state_with_a()
1150
self.build_tree(['a'])
1152
# Make sure we are using the win32 implementation of _is_executable
1153
state._is_executable = state._is_executable_win32
1155
# The file on disk is not executable, but we are marking it as though
1156
# it is. With _is_executable_win32 we ignore what is on disk.
1157
entry[1][0] = ('f', '', 0, True, dirstate.DirState.NULLSTAT)
1159
stat_value = os.lstat('a')
1160
packed_stat = dirstate.pack_stat(stat_value)
1162
state.adjust_time(-10) # Make sure everything is new
1163
self.update_entry(state, entry, abspath='a', stat_value=stat_value)
1165
# The row is updated, but the executable bit stays set.
1166
self.assertEqual([('f', '', 14, True, dirstate.DirState.NULLSTAT)],
1169
# Make the disk object look old enough to cache (but it won't cache the sha
1170
# as it is a new file).
1171
state.adjust_time(+20)
1172
digest = 'b50e5406bb5e153ebbeb20268fcf37c87e1ecfb6'
1173
self.update_entry(state, entry, abspath='a', stat_value=stat_value)
1174
self.assertEqual([('f', '', 14, True, dirstate.DirState.NULLSTAT)],
1177
def _prepare_tree(self):
1179
text = 'Hello World\n'
1180
tree = self.make_branch_and_tree('tree')
1181
self.build_tree_contents([('tree/a file', text)])
1182
tree.add('a file', 'a-file-id')
1183
# Note: dirstate does not sha prior to the first commit
1184
# so commit now in order for the test to work
1185
tree.commit('first')
1188
def test_sha1provider_sha1_used(self):
1189
tree, text = self._prepare_tree()
1190
state = dirstate.DirState.from_tree(tree, 'dirstate',
1191
UppercaseSHA1Provider())
1192
self.addCleanup(state.unlock)
1193
expected_sha = osutils.sha_string(text.upper() + "foo")
1194
entry = state._get_entry(0, path_utf8='a file')
1195
state._sha_cutoff_time()
1196
state._cutoff_time += 10
1197
sha1 = dirstate.update_entry(state, entry, 'tree/a file',
1198
os.lstat('tree/a file'))
1199
self.assertEqual(expected_sha, sha1)
1201
def test_sha1provider_stat_and_sha1_used(self):
1202
tree, text = self._prepare_tree()
1204
self.addCleanup(tree.unlock)
1205
state = tree._current_dirstate()
1206
state._sha1_provider = UppercaseSHA1Provider()
1207
# If we used the standard provider, it would look like nothing has
1209
file_ids_changed = [change[0] for change
1210
in tree.iter_changes(tree.basis_tree())]
1211
self.assertEqual(['a-file-id'], file_ids_changed)
1214
class UppercaseSHA1Provider(dirstate.SHA1Provider):
1215
"""A custom SHA1Provider."""
1217
def sha1(self, abspath):
1218
return self.stat_and_sha1(abspath)[1]
1220
def stat_and_sha1(self, abspath):
1221
file_obj = file(abspath, 'rb')
1223
statvalue = os.fstat(file_obj.fileno())
1224
text = ''.join(file_obj.readlines())
1225
sha1 = osutils.sha_string(text.upper() + "foo")
1228
return statvalue, sha1
1231
class TestCompiledUpdateEntry(TestUpdateEntry):
1232
"""Test the pyrex implementation of _read_dirblocks"""
1234
_test_needs_features = [CompiledDirstateHelpersFeature]
1236
def set_update_entry(self):
1237
from bzrlib._dirstate_helpers_c import update_entry
1238
self.update_entry = update_entry
1241
class TestProcessEntryPython(test_dirstate.TestCaseWithDirState):
1244
super(TestProcessEntryPython, self).setUp()
1245
self.setup_process_entry()
1247
def setup_process_entry(self):
1248
from bzrlib import dirstate
1249
orig = dirstate._process_entry
1251
dirstate._process_entry = orig
1252
self.addCleanup(cleanup)
1253
dirstate._process_entry = dirstate.ProcessEntryPython
1255
def assertChangedFileIds(self, expected, tree):
1258
file_ids = [info[0] for info
1259
in tree.iter_changes(tree.basis_tree())]
1262
self.assertEqual(sorted(expected), sorted(file_ids))
1264
def test_simple_changes(self):
1265
tree = self.make_branch_and_tree('tree')
1266
self.build_tree(['tree/file'])
1267
tree.add(['file'], ['file-id'])
1268
self.assertChangedFileIds([tree.get_root_id(), 'file-id'], tree)
1270
self.assertChangedFileIds([], tree)
1272
def test_sha1provider_stat_and_sha1_used(self):
1273
tree = self.make_branch_and_tree('tree')
1274
self.build_tree(['tree/file'])
1275
tree.add(['file'], ['file-id'])
1278
self.addCleanup(tree.unlock)
1279
state = tree._current_dirstate()
1280
state._sha1_provider = UppercaseSHA1Provider()
1281
self.assertChangedFileIds(['file-id'], tree)
1284
class TestProcessEntryC(TestProcessEntryPython):
1285
_test_needs_features = [CompiledDirstateHelpersFeature]
1287
def setup_process_entry(self):
1288
from bzrlib import _dirstate_helpers_c
1289
orig = dirstate._process_entry
1291
dirstate._process_entry = orig
1292
self.addCleanup(cleanup)
1293
dirstate._process_entry = _dirstate_helpers_c.ProcessEntryC