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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17
"""Tests for the compiled dirstate helpers."""
27
from bzrlib.tests import test_dirstate
30
class _CompiledDirstateHelpersFeature(tests.Feature):
33
import bzrlib._dirstate_helpers_c
38
def feature_name(self):
39
return 'bzrlib._dirstate_helpers_c'
41
CompiledDirstateHelpersFeature = _CompiledDirstateHelpersFeature()
44
class TestBisectPathMixin(object):
45
"""Test that _bisect_path_*() returns the expected values.
47
_bisect_path_* is intended to work like bisect.bisect_*() except it
48
knows it is working on paths that are sorted by ('path', 'to', 'foo')
49
chunks rather than by raw 'path/to/foo'.
51
Test Cases should inherit from this and override ``get_bisect_path`` return
52
their implementation, and ``get_bisect`` to return the matching
53
bisect.bisect_* function.
56
def get_bisect_path(self):
57
"""Return an implementation of _bisect_path_*"""
58
raise NotImplementedError
61
"""Return a version of bisect.bisect_*.
63
Also, for the 'exists' check, return the offset to the real values.
64
For example bisect_left returns the index of an entry, while
65
bisect_right returns the index *after* an entry
67
:return: (bisect_func, offset)
69
raise NotImplementedError
71
def assertBisect(self, paths, split_paths, path, exists=True):
72
"""Assert that bisect_split works like bisect_left on the split paths.
74
:param paths: A list of path names
75
:param split_paths: A list of path names that are already split up by directory
76
('path/to/foo' => ('path', 'to', 'foo'))
77
:param path: The path we are indexing.
78
:param exists: The path should be present, so make sure the
79
final location actually points to the right value.
81
All other arguments will be passed along.
83
bisect_path = self.get_bisect_path()
84
self.assertIsInstance(paths, list)
85
bisect_path_idx = bisect_path(paths, path)
86
split_path = self.split_for_dirblocks([path])[0]
87
bisect_func, offset = self.get_bisect()
88
bisect_split_idx = bisect_func(split_paths, split_path)
89
self.assertEqual(bisect_split_idx, bisect_path_idx,
90
'%s disagreed. %s != %s'
92
% (bisect_path.__name__,
93
bisect_split_idx, bisect_path_idx, path)
96
self.assertEqual(path, paths[bisect_path_idx+offset])
98
def split_for_dirblocks(self, paths):
101
dirname, basename = os.path.split(path)
102
dir_split_paths.append((dirname.split('/'), basename))
103
dir_split_paths.sort()
104
return dir_split_paths
106
def test_simple(self):
107
"""In the simple case it works just like bisect_left"""
108
paths = ['', 'a', 'b', 'c', 'd']
109
split_paths = self.split_for_dirblocks(paths)
111
self.assertBisect(paths, split_paths, path, exists=True)
112
self.assertBisect(paths, split_paths, '_', exists=False)
113
self.assertBisect(paths, split_paths, 'aa', exists=False)
114
self.assertBisect(paths, split_paths, 'bb', exists=False)
115
self.assertBisect(paths, split_paths, 'cc', exists=False)
116
self.assertBisect(paths, split_paths, 'dd', exists=False)
117
self.assertBisect(paths, split_paths, 'a/a', exists=False)
118
self.assertBisect(paths, split_paths, 'b/b', exists=False)
119
self.assertBisect(paths, split_paths, 'c/c', exists=False)
120
self.assertBisect(paths, split_paths, 'd/d', exists=False)
122
def test_involved(self):
123
"""This is where bisect_path_* diverges slightly."""
124
# This is the list of paths and their contents
152
# This is the exact order that is stored by dirstate
153
# All children in a directory are mentioned before an children of
154
# children are mentioned.
155
# So all the root-directory paths, then all the
156
# first sub directory, etc.
157
paths = [# content of '/'
158
'', 'a', 'a-a', 'a-z', 'a=a', 'a=z',
160
'a/a', 'a/a-a', 'a/a-z',
162
'a/z', 'a/z-a', 'a/z-z',
185
split_paths = self.split_for_dirblocks(paths)
187
for dir_parts, basename in split_paths:
188
if dir_parts == ['']:
189
sorted_paths.append(basename)
191
sorted_paths.append('/'.join(dir_parts + [basename]))
193
self.assertEqual(sorted_paths, paths)
196
self.assertBisect(paths, split_paths, path, exists=True)
199
class TestBisectPathLeft(tests.TestCase, TestBisectPathMixin):
200
"""Run all Bisect Path tests against _bisect_path_left_py."""
202
def get_bisect_path(self):
203
from bzrlib._dirstate_helpers_py import _bisect_path_left_py
204
return _bisect_path_left_py
206
def get_bisect(self):
207
return bisect.bisect_left, 0
210
class TestCompiledBisectPathLeft(TestBisectPathLeft):
211
"""Run all Bisect Path tests against _bisect_path_right_c"""
213
_test_needs_features = [CompiledDirstateHelpersFeature]
215
def get_bisect_path(self):
216
from bzrlib._dirstate_helpers_c import _bisect_path_left_c
217
return _bisect_path_left_c
220
class TestBisectPathRight(tests.TestCase, TestBisectPathMixin):
221
"""Run all Bisect Path tests against _bisect_path_right_py"""
223
def get_bisect_path(self):
224
from bzrlib._dirstate_helpers_py import _bisect_path_right_py
225
return _bisect_path_right_py
227
def get_bisect(self):
228
return bisect.bisect_right, -1
231
class TestCompiledBisectPathRight(TestBisectPathRight):
232
"""Run all Bisect Path tests against _bisect_path_right_c"""
234
_test_needs_features = [CompiledDirstateHelpersFeature]
236
def get_bisect_path(self):
237
from bzrlib._dirstate_helpers_c import _bisect_path_right_c
238
return _bisect_path_right_c
241
class TestBisectDirblock(tests.TestCase):
242
"""Test that bisect_dirblock() returns the expected values.
244
bisect_dirblock is intended to work like bisect.bisect_left() except it
245
knows it is working on dirblocks and that dirblocks are sorted by ('path',
246
'to', 'foo') chunks rather than by raw 'path/to/foo'.
248
This test is parameterized by calling get_bisect_dirblock(). Child test
249
cases can override this function to test against a different
253
def get_bisect_dirblock(self):
254
"""Return an implementation of bisect_dirblock"""
255
from bzrlib._dirstate_helpers_py import bisect_dirblock_py
256
return bisect_dirblock_py
258
def assertBisect(self, dirblocks, split_dirblocks, path, *args, **kwargs):
259
"""Assert that bisect_split works like bisect_left on the split paths.
261
:param dirblocks: A list of (path, [info]) pairs.
262
:param split_dirblocks: A list of ((split, path), [info]) pairs.
263
:param path: The path we are indexing.
265
All other arguments will be passed along.
267
bisect_dirblock = self.get_bisect_dirblock()
268
self.assertIsInstance(dirblocks, list)
269
bisect_split_idx = bisect_dirblock(dirblocks, path, *args, **kwargs)
270
split_dirblock = (path.split('/'), [])
271
bisect_left_idx = bisect.bisect_left(split_dirblocks, split_dirblock,
273
self.assertEqual(bisect_left_idx, bisect_split_idx,
274
'bisect_split disagreed. %s != %s'
276
% (bisect_left_idx, bisect_split_idx, path)
279
def paths_to_dirblocks(self, paths):
280
"""Convert a list of paths into dirblock form.
282
Also, ensure that the paths are in proper sorted order.
284
dirblocks = [(path, []) for path in paths]
285
split_dirblocks = [(path.split('/'), []) for path in paths]
286
self.assertEqual(sorted(split_dirblocks), split_dirblocks)
287
return dirblocks, split_dirblocks
289
def test_simple(self):
290
"""In the simple case it works just like bisect_left"""
291
paths = ['', 'a', 'b', 'c', 'd']
292
dirblocks, split_dirblocks = self.paths_to_dirblocks(paths)
294
self.assertBisect(dirblocks, split_dirblocks, path)
295
self.assertBisect(dirblocks, split_dirblocks, '_')
296
self.assertBisect(dirblocks, split_dirblocks, 'aa')
297
self.assertBisect(dirblocks, split_dirblocks, 'bb')
298
self.assertBisect(dirblocks, split_dirblocks, 'cc')
299
self.assertBisect(dirblocks, split_dirblocks, 'dd')
300
self.assertBisect(dirblocks, split_dirblocks, 'a/a')
301
self.assertBisect(dirblocks, split_dirblocks, 'b/b')
302
self.assertBisect(dirblocks, split_dirblocks, 'c/c')
303
self.assertBisect(dirblocks, split_dirblocks, 'd/d')
305
def test_involved(self):
306
"""This is where bisect_left diverges slightly."""
308
'a/a', 'a/a/a', 'a/a/z', 'a/a-a', 'a/a-z',
309
'a/z', 'a/z/a', 'a/z/z', 'a/z-a', 'a/z-z',
311
'z', 'z/a/a', 'z/a/z', 'z/a-a', 'z/a-z',
312
'z/z', 'z/z/a', 'z/z/z', 'z/z-a', 'z/z-z',
315
dirblocks, split_dirblocks = self.paths_to_dirblocks(paths)
317
self.assertBisect(dirblocks, split_dirblocks, path)
319
def test_involved_cached(self):
320
"""This is where bisect_left diverges slightly."""
322
'a/a', 'a/a/a', 'a/a/z', 'a/a-a', 'a/a-z',
323
'a/z', 'a/z/a', 'a/z/z', 'a/z-a', 'a/z-z',
325
'z', 'z/a/a', 'z/a/z', 'z/a-a', 'z/a-z',
326
'z/z', 'z/z/a', 'z/z/z', 'z/z-a', 'z/z-z',
330
dirblocks, split_dirblocks = self.paths_to_dirblocks(paths)
332
self.assertBisect(dirblocks, split_dirblocks, path, cache=cache)
335
class TestCompiledBisectDirblock(TestBisectDirblock):
336
"""Test that bisect_dirblock() returns the expected values.
338
bisect_dirblock is intended to work like bisect.bisect_left() except it
339
knows it is working on dirblocks and that dirblocks are sorted by ('path',
340
'to', 'foo') chunks rather than by raw 'path/to/foo'.
342
This runs all the normal tests that TestBisectDirblock did, but uses the
346
_test_needs_features = [CompiledDirstateHelpersFeature]
348
def get_bisect_dirblock(self):
349
from bzrlib._dirstate_helpers_c import bisect_dirblock_c
350
return bisect_dirblock_c
353
class TestCmpByDirs(tests.TestCase):
354
"""Test an implementation of cmp_by_dirs()
356
cmp_by_dirs() compares 2 paths by their directory sections, rather than as
359
Child test cases can override ``get_cmp_by_dirs`` to test a specific
363
def get_cmp_by_dirs(self):
364
"""Get a specific implementation of cmp_by_dirs."""
365
from bzrlib._dirstate_helpers_py import cmp_by_dirs_py
366
return cmp_by_dirs_py
368
def assertCmpByDirs(self, expected, str1, str2):
369
"""Compare the two strings, in both directions.
371
:param expected: The expected comparison value. -1 means str1 comes
372
first, 0 means they are equal, 1 means str2 comes first
373
:param str1: string to compare
374
:param str2: string to compare
376
cmp_by_dirs = self.get_cmp_by_dirs()
378
self.assertEqual(str1, str2)
379
self.assertEqual(0, cmp_by_dirs(str1, str2))
380
self.assertEqual(0, cmp_by_dirs(str2, str1))
382
self.assertPositive(cmp_by_dirs(str1, str2))
383
self.assertNegative(cmp_by_dirs(str2, str1))
385
self.assertNegative(cmp_by_dirs(str1, str2))
386
self.assertPositive(cmp_by_dirs(str2, str1))
388
def test_cmp_empty(self):
389
"""Compare against the empty string."""
390
self.assertCmpByDirs(0, '', '')
391
self.assertCmpByDirs(1, 'a', '')
392
self.assertCmpByDirs(1, 'ab', '')
393
self.assertCmpByDirs(1, 'abc', '')
394
self.assertCmpByDirs(1, 'abcd', '')
395
self.assertCmpByDirs(1, 'abcde', '')
396
self.assertCmpByDirs(1, 'abcdef', '')
397
self.assertCmpByDirs(1, 'abcdefg', '')
398
self.assertCmpByDirs(1, 'abcdefgh', '')
399
self.assertCmpByDirs(1, 'abcdefghi', '')
400
self.assertCmpByDirs(1, 'test/ing/a/path/', '')
402
def test_cmp_same_str(self):
403
"""Compare the same string"""
404
self.assertCmpByDirs(0, 'a', 'a')
405
self.assertCmpByDirs(0, 'ab', 'ab')
406
self.assertCmpByDirs(0, 'abc', 'abc')
407
self.assertCmpByDirs(0, 'abcd', 'abcd')
408
self.assertCmpByDirs(0, 'abcde', 'abcde')
409
self.assertCmpByDirs(0, 'abcdef', 'abcdef')
410
self.assertCmpByDirs(0, 'abcdefg', 'abcdefg')
411
self.assertCmpByDirs(0, 'abcdefgh', 'abcdefgh')
412
self.assertCmpByDirs(0, 'abcdefghi', 'abcdefghi')
413
self.assertCmpByDirs(0, 'testing a long string', 'testing a long string')
414
self.assertCmpByDirs(0, 'x'*10000, 'x'*10000)
415
self.assertCmpByDirs(0, 'a/b', 'a/b')
416
self.assertCmpByDirs(0, 'a/b/c', 'a/b/c')
417
self.assertCmpByDirs(0, 'a/b/c/d', 'a/b/c/d')
418
self.assertCmpByDirs(0, 'a/b/c/d/e', 'a/b/c/d/e')
420
def test_simple_paths(self):
421
"""Compare strings that act like normal string comparison"""
422
self.assertCmpByDirs(-1, 'a', 'b')
423
self.assertCmpByDirs(-1, 'aa', 'ab')
424
self.assertCmpByDirs(-1, 'ab', 'bb')
425
self.assertCmpByDirs(-1, 'aaa', 'aab')
426
self.assertCmpByDirs(-1, 'aab', 'abb')
427
self.assertCmpByDirs(-1, 'abb', 'bbb')
428
self.assertCmpByDirs(-1, 'aaaa', 'aaab')
429
self.assertCmpByDirs(-1, 'aaab', 'aabb')
430
self.assertCmpByDirs(-1, 'aabb', 'abbb')
431
self.assertCmpByDirs(-1, 'abbb', 'bbbb')
432
self.assertCmpByDirs(-1, 'aaaaa', 'aaaab')
433
self.assertCmpByDirs(-1, 'a/a', 'a/b')
434
self.assertCmpByDirs(-1, 'a/b', 'b/b')
435
self.assertCmpByDirs(-1, 'a/a/a', 'a/a/b')
436
self.assertCmpByDirs(-1, 'a/a/b', 'a/b/b')
437
self.assertCmpByDirs(-1, 'a/b/b', 'b/b/b')
438
self.assertCmpByDirs(-1, 'a/a/a/a', 'a/a/a/b')
439
self.assertCmpByDirs(-1, 'a/a/a/b', 'a/a/b/b')
440
self.assertCmpByDirs(-1, 'a/a/b/b', 'a/b/b/b')
441
self.assertCmpByDirs(-1, 'a/b/b/b', 'b/b/b/b')
442
self.assertCmpByDirs(-1, 'a/a/a/a/a', 'a/a/a/a/b')
444
def test_tricky_paths(self):
445
self.assertCmpByDirs(1, 'ab/cd/ef', 'ab/cc/ef')
446
self.assertCmpByDirs(1, 'ab/cd/ef', 'ab/c/ef')
447
self.assertCmpByDirs(-1, 'ab/cd/ef', 'ab/cd-ef')
448
self.assertCmpByDirs(-1, 'ab/cd', 'ab/cd-')
449
self.assertCmpByDirs(-1, 'ab/cd', 'ab-cd')
451
def test_cmp_unicode_not_allowed(self):
452
cmp_by_dirs = self.get_cmp_by_dirs()
453
self.assertRaises(TypeError, cmp_by_dirs, u'Unicode', 'str')
454
self.assertRaises(TypeError, cmp_by_dirs, 'str', u'Unicode')
455
self.assertRaises(TypeError, cmp_by_dirs, u'Unicode', u'Unicode')
457
def test_cmp_non_ascii(self):
458
self.assertCmpByDirs(-1, '\xc2\xb5', '\xc3\xa5') # u'\xb5', u'\xe5'
459
self.assertCmpByDirs(-1, 'a', '\xc3\xa5') # u'a', u'\xe5'
460
self.assertCmpByDirs(-1, 'b', '\xc2\xb5') # u'b', u'\xb5'
461
self.assertCmpByDirs(-1, 'a/b', 'a/\xc3\xa5') # u'a/b', u'a/\xe5'
462
self.assertCmpByDirs(-1, 'b/a', 'b/\xc2\xb5') # u'b/a', u'b/\xb5'
465
class TestCompiledCmpByDirs(TestCmpByDirs):
466
"""Test the pyrex implementation of cmp_by_dirs"""
468
_test_needs_features = [CompiledDirstateHelpersFeature]
470
def get_cmp_by_dirs(self):
471
from bzrlib._dirstate_helpers_c import cmp_by_dirs_c
475
class TestCmpPathByDirblock(tests.TestCase):
476
"""Test an implementation of _cmp_path_by_dirblock()
478
_cmp_path_by_dirblock() compares two paths using the sort order used by
479
DirState. All paths in the same directory are sorted together.
481
Child test cases can override ``get_cmp_path_by_dirblock`` to test a specific
485
def get_cmp_path_by_dirblock(self):
486
"""Get a specific implementation of _cmp_path_by_dirblock."""
487
from bzrlib._dirstate_helpers_py import _cmp_path_by_dirblock_py
488
return _cmp_path_by_dirblock_py
490
def assertCmpPathByDirblock(self, paths):
491
"""Compare all paths and make sure they evaluate to the correct order.
493
This does N^2 comparisons. It is assumed that ``paths`` is properly
496
:param paths: a sorted list of paths to compare
498
# First, make sure the paths being passed in are correct
500
dirname, basename = os.path.split(p)
501
return dirname.split('/'), basename
502
self.assertEqual(sorted(paths, key=_key), paths)
504
cmp_path_by_dirblock = self.get_cmp_path_by_dirblock()
505
for idx1, path1 in enumerate(paths):
506
for idx2, path2 in enumerate(paths):
507
cmp_val = cmp_path_by_dirblock(path1, path2)
509
self.assertTrue(cmp_val < 0,
510
'%s did not state that %r came before %r, cmp=%s'
511
% (cmp_path_by_dirblock.__name__,
512
path1, path2, cmp_val))
514
self.assertTrue(cmp_val > 0,
515
'%s did not state that %r came after %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 == %r, cmp=%s'
521
% (cmp_path_by_dirblock.__name__,
522
path1, path2, cmp_val))
524
def test_cmp_simple_paths(self):
525
"""Compare against the empty string."""
526
self.assertCmpPathByDirblock(['', 'a', 'ab', 'abc', 'a/b/c', 'b/d/e'])
527
self.assertCmpPathByDirblock(['kl', 'ab/cd', 'ab/ef', 'gh/ij'])
529
def test_tricky_paths(self):
530
self.assertCmpPathByDirblock([
532
'', 'a', 'a-a', 'a=a', 'b',
534
'a/a', 'a/a-a', 'a/a=a', 'a/b',
536
'a/a/a', 'a/a/a-a', 'a/a/a=a',
537
# Contents of 'a/a/a'
538
'a/a/a/a', 'a/a/a/b',
539
# Contents of 'a/a/a-a',
540
'a/a/a-a/a', 'a/a/a-a/b',
541
# Contents of 'a/a/a=a',
542
'a/a/a=a/a', 'a/a/a=a/b',
543
# Contents of 'a/a-a'
545
# Contents of 'a/a-a/a'
546
'a/a-a/a/a', 'a/a-a/a/b',
547
# Contents of 'a/a=a'
558
self.assertCmpPathByDirblock([
560
'', 'a', 'a-a', 'a-z', 'a=a', 'a=z',
562
'a/a', 'a/a-a', 'a/a-z',
564
'a/z', 'a/z-a', 'a/z-z',
588
def test_unicode_not_allowed(self):
589
cmp_path_by_dirblock = self.get_cmp_path_by_dirblock()
590
self.assertRaises(TypeError, cmp_path_by_dirblock, u'Uni', 'str')
591
self.assertRaises(TypeError, cmp_path_by_dirblock, 'str', u'Uni')
592
self.assertRaises(TypeError, cmp_path_by_dirblock, u'Uni', u'Uni')
593
self.assertRaises(TypeError, cmp_path_by_dirblock, u'x/Uni', 'x/str')
594
self.assertRaises(TypeError, cmp_path_by_dirblock, 'x/str', u'x/Uni')
595
self.assertRaises(TypeError, cmp_path_by_dirblock, u'x/Uni', u'x/Uni')
597
def test_nonascii(self):
598
self.assertCmpPathByDirblock([
600
'', 'a', '\xc2\xb5', '\xc3\xa5',
602
'a/a', 'a/\xc2\xb5', 'a/\xc3\xa5',
604
'a/a/a', 'a/a/\xc2\xb5', 'a/a/\xc3\xa5',
605
# content of 'a/\xc2\xb5'
606
'a/\xc2\xb5/a', 'a/\xc2\xb5/\xc2\xb5', 'a/\xc2\xb5/\xc3\xa5',
607
# content of 'a/\xc3\xa5'
608
'a/\xc3\xa5/a', 'a/\xc3\xa5/\xc2\xb5', 'a/\xc3\xa5/\xc3\xa5',
609
# content of '\xc2\xb5'
610
'\xc2\xb5/a', '\xc2\xb5/\xc2\xb5', '\xc2\xb5/\xc3\xa5',
611
# content of '\xc2\xe5'
612
'\xc3\xa5/a', '\xc3\xa5/\xc2\xb5', '\xc3\xa5/\xc3\xa5',
616
class TestCompiledCmpPathByDirblock(TestCmpPathByDirblock):
617
"""Test the pyrex implementation of _cmp_path_by_dirblock"""
619
_test_needs_features = [CompiledDirstateHelpersFeature]
621
def get_cmp_by_dirs(self):
622
from bzrlib._dirstate_helpers_c import _cmp_path_by_dirblock_c
623
return _cmp_path_by_dirblock_c
626
class TestMemRChr(tests.TestCase):
627
"""Test memrchr functionality"""
629
_test_needs_features = [CompiledDirstateHelpersFeature]
631
def assertMemRChr(self, expected, s, c):
632
from bzrlib._dirstate_helpers_c import _py_memrchr
633
self.assertEqual(expected, _py_memrchr(s, c))
635
def test_missing(self):
636
self.assertMemRChr(None, '', 'a')
637
self.assertMemRChr(None, '', 'c')
638
self.assertMemRChr(None, 'abcdefghijklm', 'q')
639
self.assertMemRChr(None, 'aaaaaaaaaaaaaaaaaaaaaaa', 'b')
641
def test_single_entry(self):
642
self.assertMemRChr(0, 'abcdefghijklm', 'a')
643
self.assertMemRChr(1, 'abcdefghijklm', 'b')
644
self.assertMemRChr(2, 'abcdefghijklm', 'c')
645
self.assertMemRChr(10, 'abcdefghijklm', 'k')
646
self.assertMemRChr(11, 'abcdefghijklm', 'l')
647
self.assertMemRChr(12, 'abcdefghijklm', 'm')
649
def test_multiple(self):
650
self.assertMemRChr(10, 'abcdefjklmabcdefghijklm', 'a')
651
self.assertMemRChr(11, 'abcdefjklmabcdefghijklm', 'b')
652
self.assertMemRChr(12, 'abcdefjklmabcdefghijklm', 'c')
653
self.assertMemRChr(20, 'abcdefjklmabcdefghijklm', 'k')
654
self.assertMemRChr(21, 'abcdefjklmabcdefghijklm', 'l')
655
self.assertMemRChr(22, 'abcdefjklmabcdefghijklm', 'm')
656
self.assertMemRChr(22, 'aaaaaaaaaaaaaaaaaaaaaaa', 'a')
658
def test_with_nulls(self):
659
self.assertMemRChr(10, 'abc\0\0\0jklmabc\0\0\0ghijklm', 'a')
660
self.assertMemRChr(11, 'abc\0\0\0jklmabc\0\0\0ghijklm', 'b')
661
self.assertMemRChr(12, 'abc\0\0\0jklmabc\0\0\0ghijklm', 'c')
662
self.assertMemRChr(20, 'abc\0\0\0jklmabc\0\0\0ghijklm', 'k')
663
self.assertMemRChr(21, 'abc\0\0\0jklmabc\0\0\0ghijklm', 'l')
664
self.assertMemRChr(22, 'abc\0\0\0jklmabc\0\0\0ghijklm', 'm')
665
self.assertMemRChr(22, 'aaa\0\0\0aaaaaaa\0\0\0aaaaaaa', 'a')
666
self.assertMemRChr(9, '\0\0\0\0\0\0\0\0\0\0', '\0')
669
class TestReadDirblocks(test_dirstate.TestCaseWithDirState):
670
"""Test an implementation of _read_dirblocks()
672
_read_dirblocks() reads in all of the dirblock information from the disk
675
Child test cases can override ``get_read_dirblocks`` to test a specific
679
def get_read_dirblocks(self):
680
from bzrlib._dirstate_helpers_py import _read_dirblocks_py
681
return _read_dirblocks_py
683
def test_smoketest(self):
684
"""Make sure that we can create and read back a simple file."""
685
tree, state, expected = self.create_basic_dirstate()
687
state._read_header_if_needed()
688
self.assertEqual(dirstate.DirState.NOT_IN_MEMORY,
689
state._dirblock_state)
690
read_dirblocks = self.get_read_dirblocks()
691
read_dirblocks(state)
692
self.assertEqual(dirstate.DirState.IN_MEMORY_UNMODIFIED,
693
state._dirblock_state)
695
def test_trailing_garbage(self):
696
tree, state, expected = self.create_basic_dirstate()
697
# We can modify the file as long as it hasn't been read yet.
698
f = open('dirstate', 'ab')
700
# Add bogus trailing garbage
704
e = self.assertRaises(errors.DirstateCorrupt,
705
state._read_dirblocks_if_needed)
706
# Make sure we mention the bogus characters in the error
707
self.assertContainsRe(str(e), 'bogus')
710
class TestCompiledReadDirblocks(TestReadDirblocks):
711
"""Test the pyrex implementation of _read_dirblocks"""
713
_test_needs_features = [CompiledDirstateHelpersFeature]
715
def get_read_dirblocks(self):
716
from bzrlib._dirstate_helpers_c import _read_dirblocks_c
717
return _read_dirblocks_c
720
class TestUsingCompiledIfAvailable(tests.TestCase):
721
"""Check that any compiled functions that are available are the default.
723
It is possible to have typos, etc in the import line, such that
724
_dirstate_helpers_c is actually available, but the compiled functions are
728
def test_bisect_dirblock(self):
729
if CompiledDirstateHelpersFeature.available():
730
from bzrlib._dirstate_helpers_c import bisect_dirblock_c
731
self.assertIs(bisect_dirblock_c, dirstate.bisect_dirblock)
733
from bzrlib._dirstate_helpers_py import bisect_dirblock_py
734
self.assertIs(bisect_dirblock_py, dirstate.bisect_dirblock)
736
def test__bisect_path_left(self):
737
if CompiledDirstateHelpersFeature.available():
738
from bzrlib._dirstate_helpers_c import _bisect_path_left_c
739
self.assertIs(_bisect_path_left_c, dirstate._bisect_path_left)
741
from bzrlib._dirstate_helpers_py import _bisect_path_left_py
742
self.assertIs(_bisect_path_left_py, dirstate._bisect_path_left)
744
def test__bisect_path_right(self):
745
if CompiledDirstateHelpersFeature.available():
746
from bzrlib._dirstate_helpers_c import _bisect_path_right_c
747
self.assertIs(_bisect_path_right_c, dirstate._bisect_path_right)
749
from bzrlib._dirstate_helpers_py import _bisect_path_right_py
750
self.assertIs(_bisect_path_right_py, dirstate._bisect_path_right)
752
def test_cmp_by_dirs(self):
753
if CompiledDirstateHelpersFeature.available():
754
from bzrlib._dirstate_helpers_c import cmp_by_dirs_c
755
self.assertIs(cmp_by_dirs_c, dirstate.cmp_by_dirs)
757
from bzrlib._dirstate_helpers_py import cmp_by_dirs_py
758
self.assertIs(cmp_by_dirs_py, dirstate.cmp_by_dirs)
760
def test__read_dirblocks(self):
761
if CompiledDirstateHelpersFeature.available():
762
from bzrlib._dirstate_helpers_c import _read_dirblocks_c
763
self.assertIs(_read_dirblocks_c, dirstate._read_dirblocks)
765
from bzrlib._dirstate_helpers_py import _read_dirblocks_py
766
self.assertIs(_read_dirblocks_py, dirstate._read_dirblocks)