/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 breezy/tests/test__dirstate_helpers.py

  • Committer: Jelmer Vernooij
  • Date: 2018-08-14 01:15:02 UTC
  • mto: This revision was merged to the branch mainline in revision 7078.
  • Revision ID: jelmer@jelmer.uk-20180814011502-5zaydaq02vc2qxo1
Fix tests.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2007-2010 Canonical Ltd
 
1
# Copyright (C) 2007-2011 Canonical Ltd
2
2
#
3
3
# This program is free software; you can redistribute it and/or modify
4
4
# it under the terms of the GNU General Public License as published by
20
20
import os
21
21
import time
22
22
 
23
 
from bzrlib import (
24
 
    dirstate,
25
 
    errors,
 
23
from .. import (
26
24
    osutils,
27
25
    tests,
28
26
    )
29
 
from bzrlib.tests import (
 
27
from ..bzr import (
 
28
    dirstate,
 
29
    _dirstate_helpers_py,
 
30
    )
 
31
from . import (
30
32
    test_dirstate,
31
 
    test_osutils,
32
 
    )
33
 
 
34
 
try:
35
 
    from bzrlib import _dirstate_helpers_pyx
36
 
    has_dirstate_helpers_pyx = True
37
 
except ImportError:
38
 
    has_dirstate_helpers_pyx = False
39
 
 
40
 
 
41
 
compiled_dirstate_helpers_feature = tests.ModuleAvailableFeature(
42
 
                                'bzrlib._dirstate_helpers_pyx')
43
 
 
44
 
 
45
 
def load_tests(basic_tests, module, loader):
46
 
    # FIXME: we should also parametrize against SHA1Provider !
47
 
    suite = loader.suiteClass()
48
 
    remaining_tests = basic_tests
49
 
 
50
 
    dir_reader_scenarios = test_osutils.dir_reader_scenarios()
51
 
 
52
 
    ue_scenarios = [('dirstate_Python',
53
 
                     {'update_entry': dirstate.py_update_entry})]
54
 
    if compiled_dirstate_helpers_feature.available():
55
 
        update_entry = compiled_dirstate_helpers_feature.module.update_entry
56
 
        pyrex_scenario = ('dirstate_Pyrex', {'update_entry': update_entry})
57
 
        ue_scenarios.append(pyrex_scenario)
58
 
    process_entry_tests, remaining_tests = tests.split_suite_by_condition(
59
 
        remaining_tests, tests.condition_isinstance(TestUpdateEntry))
60
 
    tests.multiply_tests(process_entry_tests,
61
 
                         tests.multiply_scenarios(dir_reader_scenarios,
62
 
                                                  ue_scenarios),
63
 
                         suite)
64
 
 
65
 
    pe_scenarios = [('dirstate_Python',
66
 
                     {'_process_entry': dirstate.ProcessEntryPython})]
67
 
    if compiled_dirstate_helpers_feature.available():
68
 
        process_entry = compiled_dirstate_helpers_feature.module.ProcessEntryC
69
 
        pyrex_scenario = ('dirstate_Pyrex', {'_process_entry': process_entry})
70
 
        pe_scenarios.append(pyrex_scenario)
71
 
    process_entry_tests, remaining_tests = tests.split_suite_by_condition(
72
 
        remaining_tests, tests.condition_isinstance(TestProcessEntry))
73
 
    tests.multiply_tests(process_entry_tests,
74
 
                         tests.multiply_scenarios(dir_reader_scenarios,
75
 
                                                  pe_scenarios),
76
 
                         suite)
77
 
 
78
 
    dir_reader_tests, remaining_tests = tests.split_suite_by_condition(
79
 
        remaining_tests, tests.condition_isinstance(
80
 
            test_dirstate.TestCaseWithDirState))
81
 
    tests.multiply_tests(dir_reader_tests, dir_reader_scenarios, suite)
82
 
    suite.addTest(remaining_tests)
83
 
 
84
 
    return suite
 
33
    )
 
34
from .test_osutils import dir_reader_scenarios
 
35
from .scenarios import (
 
36
    load_tests_apply_scenarios,
 
37
    multiply_scenarios,
 
38
    )
 
39
from . import (
 
40
    features,
 
41
    )
 
42
 
 
43
 
 
44
load_tests = load_tests_apply_scenarios
 
45
 
 
46
 
 
47
compiled_dirstate_helpers_feature = features.ModuleAvailableFeature(
 
48
    'breezy.bzr._dirstate_helpers_pyx')
 
49
 
 
50
 
 
51
# FIXME: we should also parametrize against SHA1Provider !
 
52
 
 
53
ue_scenarios = [('dirstate_Python',
 
54
    {'update_entry': dirstate.py_update_entry})]
 
55
if compiled_dirstate_helpers_feature.available():
 
56
    update_entry = compiled_dirstate_helpers_feature.module.update_entry
 
57
    ue_scenarios.append(('dirstate_Pyrex', {'update_entry': update_entry}))
 
58
 
 
59
pe_scenarios = [('dirstate_Python',
 
60
    {'_process_entry': dirstate.ProcessEntryPython})]
 
61
if compiled_dirstate_helpers_feature.available():
 
62
    process_entry = compiled_dirstate_helpers_feature.module.ProcessEntryC
 
63
    pe_scenarios.append(('dirstate_Pyrex', {'_process_entry': process_entry}))
 
64
 
 
65
helper_scenarios = [('dirstate_Python', {'helpers': _dirstate_helpers_py})]
 
66
if compiled_dirstate_helpers_feature.available():
 
67
    helper_scenarios.append(('dirstate_Pyrex',
 
68
        {'helpers': compiled_dirstate_helpers_feature.module}))
85
69
 
86
70
 
87
71
class TestBisectPathMixin(object):
142
126
        dir_split_paths = []
143
127
        for path in paths:
144
128
            dirname, basename = os.path.split(path)
145
 
            dir_split_paths.append((dirname.split('/'), basename))
 
129
            dir_split_paths.append((dirname.split(b'/'), basename))
146
130
        dir_split_paths.sort()
147
131
        return dir_split_paths
148
132
 
149
133
    def test_simple(self):
150
134
        """In the simple case it works just like bisect_left"""
151
 
        paths = ['', 'a', 'b', 'c', 'd']
 
135
        paths = [b'', b'a', b'b', b'c', b'd']
152
136
        split_paths = self.split_for_dirblocks(paths)
153
137
        for path in paths:
154
138
            self.assertBisect(paths, split_paths, path, exists=True)
155
 
        self.assertBisect(paths, split_paths, '_', exists=False)
156
 
        self.assertBisect(paths, split_paths, 'aa', exists=False)
157
 
        self.assertBisect(paths, split_paths, 'bb', exists=False)
158
 
        self.assertBisect(paths, split_paths, 'cc', exists=False)
159
 
        self.assertBisect(paths, split_paths, 'dd', exists=False)
160
 
        self.assertBisect(paths, split_paths, 'a/a', exists=False)
161
 
        self.assertBisect(paths, split_paths, 'b/b', exists=False)
162
 
        self.assertBisect(paths, split_paths, 'c/c', exists=False)
163
 
        self.assertBisect(paths, split_paths, 'd/d', exists=False)
 
139
        self.assertBisect(paths, split_paths, b'_', exists=False)
 
140
        self.assertBisect(paths, split_paths, b'aa', exists=False)
 
141
        self.assertBisect(paths, split_paths, b'bb', exists=False)
 
142
        self.assertBisect(paths, split_paths, b'cc', exists=False)
 
143
        self.assertBisect(paths, split_paths, b'dd', exists=False)
 
144
        self.assertBisect(paths, split_paths, b'a/a', exists=False)
 
145
        self.assertBisect(paths, split_paths, b'b/b', exists=False)
 
146
        self.assertBisect(paths, split_paths, b'c/c', exists=False)
 
147
        self.assertBisect(paths, split_paths, b'd/d', exists=False)
164
148
 
165
149
    def test_involved(self):
166
150
        """This is where bisect_path_* diverges slightly."""
198
182
        # So all the root-directory paths, then all the
199
183
        # first sub directory, etc.
200
184
        paths = [# content of '/'
201
 
                 '', 'a', 'a-a', 'a-z', 'a=a', 'a=z',
 
185
                 b'', b'a', b'a-a', b'a-z', b'a=a', b'a=z',
202
186
                 # content of 'a/'
203
 
                 'a/a', 'a/a-a', 'a/a-z',
204
 
                 'a/a=a', 'a/a=z',
205
 
                 'a/z', 'a/z-a', 'a/z-z',
206
 
                 'a/z=a', 'a/z=z',
 
187
                 b'a/a', b'a/a-a', b'a/a-z',
 
188
                 b'a/a=a', b'a/a=z',
 
189
                 b'a/z', b'a/z-a', b'a/z-z',
 
190
                 b'a/z=a', b'a/z=z',
207
191
                 # content of 'a/a/'
208
 
                 'a/a/a', 'a/a/z',
 
192
                 b'a/a/a', b'a/a/z',
209
193
                 # content of 'a/a-a'
210
 
                 'a/a-a/a',
 
194
                 b'a/a-a/a',
211
195
                 # content of 'a/a-z'
212
 
                 'a/a-z/z',
 
196
                 b'a/a-z/z',
213
197
                 # content of 'a/a=a'
214
 
                 'a/a=a/a',
 
198
                 b'a/a=a/a',
215
199
                 # content of 'a/a=z'
216
 
                 'a/a=z/z',
 
200
                 b'a/a=z/z',
217
201
                 # content of 'a/z/'
218
 
                 'a/z/a', 'a/z/z',
 
202
                 b'a/z/a', b'a/z/z',
219
203
                 # content of 'a-a'
220
 
                 'a-a/a',
 
204
                 b'a-a/a',
221
205
                 # content of 'a-z'
222
 
                 'a-z/z',
 
206
                 b'a-z/z',
223
207
                 # content of 'a=a'
224
 
                 'a=a/a',
 
208
                 b'a=a/a',
225
209
                 # content of 'a=z'
226
 
                 'a=z/z',
 
210
                 b'a=z/z',
227
211
                ]
228
212
        split_paths = self.split_for_dirblocks(paths)
229
213
        sorted_paths = []
230
214
        for dir_parts, basename in split_paths:
231
 
            if dir_parts == ['']:
 
215
            if dir_parts == [b'']:
232
216
                sorted_paths.append(basename)
233
217
            else:
234
 
                sorted_paths.append('/'.join(dir_parts + [basename]))
 
218
                sorted_paths.append(b'/'.join(dir_parts + [basename]))
235
219
 
236
220
        self.assertEqual(sorted_paths, paths)
237
221
 
243
227
    """Run all Bisect Path tests against _bisect_path_left."""
244
228
 
245
229
    def get_bisect_path(self):
246
 
        from bzrlib._dirstate_helpers_py import _bisect_path_left
 
230
        from breezy.bzr._dirstate_helpers_py import _bisect_path_left
247
231
        return _bisect_path_left
248
232
 
249
233
    def get_bisect(self):
256
240
    _test_needs_features = [compiled_dirstate_helpers_feature]
257
241
 
258
242
    def get_bisect_path(self):
259
 
        from bzrlib._dirstate_helpers_pyx import _bisect_path_left
 
243
        from breezy.bzr._dirstate_helpers_pyx import _bisect_path_left
260
244
        return _bisect_path_left
261
245
 
262
246
 
264
248
    """Run all Bisect Path tests against _bisect_path_right"""
265
249
 
266
250
    def get_bisect_path(self):
267
 
        from bzrlib._dirstate_helpers_py import _bisect_path_right
 
251
        from breezy.bzr._dirstate_helpers_py import _bisect_path_right
268
252
        return _bisect_path_right
269
253
 
270
254
    def get_bisect(self):
277
261
    _test_needs_features = [compiled_dirstate_helpers_feature]
278
262
 
279
263
    def get_bisect_path(self):
280
 
        from bzrlib._dirstate_helpers_pyx import _bisect_path_right
 
264
        from breezy.bzr._dirstate_helpers_pyx import _bisect_path_right
281
265
        return _bisect_path_right
282
266
 
283
267
 
295
279
 
296
280
    def get_bisect_dirblock(self):
297
281
        """Return an implementation of bisect_dirblock"""
298
 
        from bzrlib._dirstate_helpers_py import bisect_dirblock
 
282
        from breezy.bzr._dirstate_helpers_py import bisect_dirblock
299
283
        return bisect_dirblock
300
284
 
301
285
    def assertBisect(self, dirblocks, split_dirblocks, path, *args, **kwargs):
310
294
        bisect_dirblock = self.get_bisect_dirblock()
311
295
        self.assertIsInstance(dirblocks, list)
312
296
        bisect_split_idx = bisect_dirblock(dirblocks, path, *args, **kwargs)
313
 
        split_dirblock = (path.split('/'), [])
 
297
        split_dirblock = (path.split(b'/'), [])
314
298
        bisect_left_idx = bisect.bisect_left(split_dirblocks, split_dirblock,
315
299
                                             *args)
316
300
        self.assertEqual(bisect_left_idx, bisect_split_idx,
325
309
        Also, ensure that the paths are in proper sorted order.
326
310
        """
327
311
        dirblocks = [(path, []) for path in paths]
328
 
        split_dirblocks = [(path.split('/'), []) for path in paths]
 
312
        split_dirblocks = [(path.split(b'/'), []) for path in paths]
329
313
        self.assertEqual(sorted(split_dirblocks), split_dirblocks)
330
314
        return dirblocks, split_dirblocks
331
315
 
332
316
    def test_simple(self):
333
317
        """In the simple case it works just like bisect_left"""
334
 
        paths = ['', 'a', 'b', 'c', 'd']
 
318
        paths = [b'', b'a', b'b', b'c', b'd']
335
319
        dirblocks, split_dirblocks = self.paths_to_dirblocks(paths)
336
320
        for path in paths:
337
321
            self.assertBisect(dirblocks, split_dirblocks, path)
338
 
        self.assertBisect(dirblocks, split_dirblocks, '_')
339
 
        self.assertBisect(dirblocks, split_dirblocks, 'aa')
340
 
        self.assertBisect(dirblocks, split_dirblocks, 'bb')
341
 
        self.assertBisect(dirblocks, split_dirblocks, 'cc')
342
 
        self.assertBisect(dirblocks, split_dirblocks, 'dd')
343
 
        self.assertBisect(dirblocks, split_dirblocks, 'a/a')
344
 
        self.assertBisect(dirblocks, split_dirblocks, 'b/b')
345
 
        self.assertBisect(dirblocks, split_dirblocks, 'c/c')
346
 
        self.assertBisect(dirblocks, split_dirblocks, 'd/d')
 
322
        self.assertBisect(dirblocks, split_dirblocks, b'_')
 
323
        self.assertBisect(dirblocks, split_dirblocks, b'aa')
 
324
        self.assertBisect(dirblocks, split_dirblocks, b'bb')
 
325
        self.assertBisect(dirblocks, split_dirblocks, b'cc')
 
326
        self.assertBisect(dirblocks, split_dirblocks, b'dd')
 
327
        self.assertBisect(dirblocks, split_dirblocks, b'a/a')
 
328
        self.assertBisect(dirblocks, split_dirblocks, b'b/b')
 
329
        self.assertBisect(dirblocks, split_dirblocks, b'c/c')
 
330
        self.assertBisect(dirblocks, split_dirblocks, b'd/d')
347
331
 
348
332
    def test_involved(self):
349
333
        """This is where bisect_left diverges slightly."""
350
 
        paths = ['', 'a',
351
 
                 'a/a', 'a/a/a', 'a/a/z', 'a/a-a', 'a/a-z',
352
 
                 'a/z', 'a/z/a', 'a/z/z', 'a/z-a', 'a/z-z',
353
 
                 'a-a', 'a-z',
354
 
                 'z', 'z/a/a', 'z/a/z', 'z/a-a', 'z/a-z',
355
 
                 'z/z', 'z/z/a', 'z/z/z', 'z/z-a', 'z/z-z',
356
 
                 'z-a', 'z-z',
 
334
        paths = [b'', b'a',
 
335
                 b'a/a', b'a/a/a', b'a/a/z', b'a/a-a', b'a/a-z',
 
336
                 b'a/z', b'a/z/a', b'a/z/z', b'a/z-a', b'a/z-z',
 
337
                 b'a-a', b'a-z',
 
338
                 b'z', b'z/a/a', b'z/a/z', b'z/a-a', b'z/a-z',
 
339
                 b'z/z', b'z/z/a', b'z/z/z', b'z/z-a', b'z/z-z',
 
340
                 b'z-a', b'z-z',
357
341
                ]
358
342
        dirblocks, split_dirblocks = self.paths_to_dirblocks(paths)
359
343
        for path in paths:
361
345
 
362
346
    def test_involved_cached(self):
363
347
        """This is where bisect_left diverges slightly."""
364
 
        paths = ['', 'a',
365
 
                 'a/a', 'a/a/a', 'a/a/z', 'a/a-a', 'a/a-z',
366
 
                 'a/z', 'a/z/a', 'a/z/z', 'a/z-a', 'a/z-z',
367
 
                 'a-a', 'a-z',
368
 
                 'z', 'z/a/a', 'z/a/z', 'z/a-a', 'z/a-z',
369
 
                 'z/z', 'z/z/a', 'z/z/z', 'z/z-a', 'z/z-z',
370
 
                 'z-a', 'z-z',
 
348
        paths = [b'', b'a',
 
349
                 b'a/a', b'a/a/a', b'a/a/z', b'a/a-a', b'a/a-z',
 
350
                 b'a/z', b'a/z/a', b'a/z/z', b'a/z-a', b'a/z-z',
 
351
                 b'a-a', b'a-z',
 
352
                 b'z', b'z/a/a', b'z/a/z', b'z/a-a', b'z/a-z',
 
353
                 b'z/z', b'z/z/a', b'z/z/z', b'z/z-a', b'z/z-z',
 
354
                 b'z-a', b'z-z',
371
355
                ]
372
356
        cache = {}
373
357
        dirblocks, split_dirblocks = self.paths_to_dirblocks(paths)
389
373
    _test_needs_features = [compiled_dirstate_helpers_feature]
390
374
 
391
375
    def get_bisect_dirblock(self):
392
 
        from bzrlib._dirstate_helpers_pyx import bisect_dirblock
 
376
        from breezy.bzr._dirstate_helpers_pyx import bisect_dirblock
393
377
        return bisect_dirblock
394
378
 
395
379
 
396
 
class TestCmpByDirs(tests.TestCase):
397
 
    """Test an implementation of cmp_by_dirs()
 
380
class TestLtByDirs(tests.TestCase):
 
381
    """Test an implementation of lt_by_dirs()
398
382
 
399
 
    cmp_by_dirs() compares 2 paths by their directory sections, rather than as
 
383
    lt_by_dirs() compares 2 paths by their directory sections, rather than as
400
384
    plain strings.
401
385
 
402
 
    Child test cases can override ``get_cmp_by_dirs`` to test a specific
 
386
    Child test cases can override ``get_lt_by_dirs`` to test a specific
403
387
    implementation.
404
388
    """
405
389
 
406
 
    def get_cmp_by_dirs(self):
407
 
        """Get a specific implementation of cmp_by_dirs."""
408
 
        from bzrlib._dirstate_helpers_py import cmp_by_dirs
409
 
        return cmp_by_dirs
 
390
    def get_lt_by_dirs(self):
 
391
        """Get a specific implementation of lt_by_dirs."""
 
392
        from ..bzr._dirstate_helpers_py import lt_by_dirs
 
393
        return lt_by_dirs
410
394
 
411
395
    def assertCmpByDirs(self, expected, str1, str2):
412
396
        """Compare the two strings, in both directions.
416
400
        :param str1: string to compare
417
401
        :param str2: string to compare
418
402
        """
419
 
        cmp_by_dirs = self.get_cmp_by_dirs()
 
403
        lt_by_dirs = self.get_lt_by_dirs()
420
404
        if expected == 0:
421
405
            self.assertEqual(str1, str2)
422
 
            self.assertEqual(0, cmp_by_dirs(str1, str2))
423
 
            self.assertEqual(0, cmp_by_dirs(str2, str1))
 
406
            self.assertFalse(lt_by_dirs(str1, str2))
 
407
            self.assertFalse(lt_by_dirs(str2, str1))
424
408
        elif expected > 0:
425
 
            self.assertPositive(cmp_by_dirs(str1, str2))
426
 
            self.assertNegative(cmp_by_dirs(str2, str1))
 
409
            self.assertFalse(lt_by_dirs(str1, str2))
 
410
            self.assertTrue(lt_by_dirs(str2, str1))
427
411
        else:
428
 
            self.assertNegative(cmp_by_dirs(str1, str2))
429
 
            self.assertPositive(cmp_by_dirs(str2, str1))
 
412
            self.assertTrue(lt_by_dirs(str1, str2))
 
413
            self.assertFalse(lt_by_dirs(str2, str1))
430
414
 
431
415
    def test_cmp_empty(self):
432
416
        """Compare against the empty string."""
433
 
        self.assertCmpByDirs(0, '', '')
434
 
        self.assertCmpByDirs(1, 'a', '')
435
 
        self.assertCmpByDirs(1, 'ab', '')
436
 
        self.assertCmpByDirs(1, 'abc', '')
437
 
        self.assertCmpByDirs(1, 'abcd', '')
438
 
        self.assertCmpByDirs(1, 'abcde', '')
439
 
        self.assertCmpByDirs(1, 'abcdef', '')
440
 
        self.assertCmpByDirs(1, 'abcdefg', '')
441
 
        self.assertCmpByDirs(1, 'abcdefgh', '')
442
 
        self.assertCmpByDirs(1, 'abcdefghi', '')
443
 
        self.assertCmpByDirs(1, 'test/ing/a/path/', '')
 
417
        self.assertCmpByDirs(0, b'', b'')
 
418
        self.assertCmpByDirs(1, b'a', b'')
 
419
        self.assertCmpByDirs(1, b'ab', b'')
 
420
        self.assertCmpByDirs(1, b'abc', b'')
 
421
        self.assertCmpByDirs(1, b'abcd', b'')
 
422
        self.assertCmpByDirs(1, b'abcde', b'')
 
423
        self.assertCmpByDirs(1, b'abcdef', b'')
 
424
        self.assertCmpByDirs(1, b'abcdefg', b'')
 
425
        self.assertCmpByDirs(1, b'abcdefgh', b'')
 
426
        self.assertCmpByDirs(1, b'abcdefghi', b'')
 
427
        self.assertCmpByDirs(1, b'test/ing/a/path/', b'')
444
428
 
445
429
    def test_cmp_same_str(self):
446
430
        """Compare the same string"""
447
 
        self.assertCmpByDirs(0, 'a', 'a')
448
 
        self.assertCmpByDirs(0, 'ab', 'ab')
449
 
        self.assertCmpByDirs(0, 'abc', 'abc')
450
 
        self.assertCmpByDirs(0, 'abcd', 'abcd')
451
 
        self.assertCmpByDirs(0, 'abcde', 'abcde')
452
 
        self.assertCmpByDirs(0, 'abcdef', 'abcdef')
453
 
        self.assertCmpByDirs(0, 'abcdefg', 'abcdefg')
454
 
        self.assertCmpByDirs(0, 'abcdefgh', 'abcdefgh')
455
 
        self.assertCmpByDirs(0, 'abcdefghi', 'abcdefghi')
456
 
        self.assertCmpByDirs(0, 'testing a long string', 'testing a long string')
457
 
        self.assertCmpByDirs(0, 'x'*10000, 'x'*10000)
458
 
        self.assertCmpByDirs(0, 'a/b', 'a/b')
459
 
        self.assertCmpByDirs(0, 'a/b/c', 'a/b/c')
460
 
        self.assertCmpByDirs(0, 'a/b/c/d', 'a/b/c/d')
461
 
        self.assertCmpByDirs(0, 'a/b/c/d/e', 'a/b/c/d/e')
 
431
        self.assertCmpByDirs(0, b'a', b'a')
 
432
        self.assertCmpByDirs(0, b'ab', b'ab')
 
433
        self.assertCmpByDirs(0, b'abc', b'abc')
 
434
        self.assertCmpByDirs(0, b'abcd', b'abcd')
 
435
        self.assertCmpByDirs(0, b'abcde', b'abcde')
 
436
        self.assertCmpByDirs(0, b'abcdef', b'abcdef')
 
437
        self.assertCmpByDirs(0, b'abcdefg', b'abcdefg')
 
438
        self.assertCmpByDirs(0, b'abcdefgh', b'abcdefgh')
 
439
        self.assertCmpByDirs(0, b'abcdefghi', b'abcdefghi')
 
440
        self.assertCmpByDirs(0, b'testing a long string', b'testing a long string')
 
441
        self.assertCmpByDirs(0, b'x'*10000, b'x'*10000)
 
442
        self.assertCmpByDirs(0, b'a/b', b'a/b')
 
443
        self.assertCmpByDirs(0, b'a/b/c', b'a/b/c')
 
444
        self.assertCmpByDirs(0, b'a/b/c/d', b'a/b/c/d')
 
445
        self.assertCmpByDirs(0, b'a/b/c/d/e', b'a/b/c/d/e')
462
446
 
463
447
    def test_simple_paths(self):
464
448
        """Compare strings that act like normal string comparison"""
465
 
        self.assertCmpByDirs(-1, 'a', 'b')
466
 
        self.assertCmpByDirs(-1, 'aa', 'ab')
467
 
        self.assertCmpByDirs(-1, 'ab', 'bb')
468
 
        self.assertCmpByDirs(-1, 'aaa', 'aab')
469
 
        self.assertCmpByDirs(-1, 'aab', 'abb')
470
 
        self.assertCmpByDirs(-1, 'abb', 'bbb')
471
 
        self.assertCmpByDirs(-1, 'aaaa', 'aaab')
472
 
        self.assertCmpByDirs(-1, 'aaab', 'aabb')
473
 
        self.assertCmpByDirs(-1, 'aabb', 'abbb')
474
 
        self.assertCmpByDirs(-1, 'abbb', 'bbbb')
475
 
        self.assertCmpByDirs(-1, 'aaaaa', 'aaaab')
476
 
        self.assertCmpByDirs(-1, 'a/a', 'a/b')
477
 
        self.assertCmpByDirs(-1, 'a/b', 'b/b')
478
 
        self.assertCmpByDirs(-1, 'a/a/a', 'a/a/b')
479
 
        self.assertCmpByDirs(-1, 'a/a/b', 'a/b/b')
480
 
        self.assertCmpByDirs(-1, 'a/b/b', 'b/b/b')
481
 
        self.assertCmpByDirs(-1, 'a/a/a/a', 'a/a/a/b')
482
 
        self.assertCmpByDirs(-1, 'a/a/a/b', 'a/a/b/b')
483
 
        self.assertCmpByDirs(-1, 'a/a/b/b', 'a/b/b/b')
484
 
        self.assertCmpByDirs(-1, 'a/b/b/b', 'b/b/b/b')
485
 
        self.assertCmpByDirs(-1, 'a/a/a/a/a', 'a/a/a/a/b')
 
449
        self.assertCmpByDirs(-1, b'a', b'b')
 
450
        self.assertCmpByDirs(-1, b'aa', b'ab')
 
451
        self.assertCmpByDirs(-1, b'ab', b'bb')
 
452
        self.assertCmpByDirs(-1, b'aaa', b'aab')
 
453
        self.assertCmpByDirs(-1, b'aab', b'abb')
 
454
        self.assertCmpByDirs(-1, b'abb', b'bbb')
 
455
        self.assertCmpByDirs(-1, b'aaaa', b'aaab')
 
456
        self.assertCmpByDirs(-1, b'aaab', b'aabb')
 
457
        self.assertCmpByDirs(-1, b'aabb', b'abbb')
 
458
        self.assertCmpByDirs(-1, b'abbb', b'bbbb')
 
459
        self.assertCmpByDirs(-1, b'aaaaa', b'aaaab')
 
460
        self.assertCmpByDirs(-1, b'a/a', b'a/b')
 
461
        self.assertCmpByDirs(-1, b'a/b', b'b/b')
 
462
        self.assertCmpByDirs(-1, b'a/a/a', b'a/a/b')
 
463
        self.assertCmpByDirs(-1, b'a/a/b', b'a/b/b')
 
464
        self.assertCmpByDirs(-1, b'a/b/b', b'b/b/b')
 
465
        self.assertCmpByDirs(-1, b'a/a/a/a', b'a/a/a/b')
 
466
        self.assertCmpByDirs(-1, b'a/a/a/b', b'a/a/b/b')
 
467
        self.assertCmpByDirs(-1, b'a/a/b/b', b'a/b/b/b')
 
468
        self.assertCmpByDirs(-1, b'a/b/b/b', b'b/b/b/b')
 
469
        self.assertCmpByDirs(-1, b'a/a/a/a/a', b'a/a/a/a/b')
486
470
 
487
471
    def test_tricky_paths(self):
488
 
        self.assertCmpByDirs(1, 'ab/cd/ef', 'ab/cc/ef')
489
 
        self.assertCmpByDirs(1, 'ab/cd/ef', 'ab/c/ef')
490
 
        self.assertCmpByDirs(-1, 'ab/cd/ef', 'ab/cd-ef')
491
 
        self.assertCmpByDirs(-1, 'ab/cd', 'ab/cd-')
492
 
        self.assertCmpByDirs(-1, 'ab/cd', 'ab-cd')
 
472
        self.assertCmpByDirs(1, b'ab/cd/ef', b'ab/cc/ef')
 
473
        self.assertCmpByDirs(1, b'ab/cd/ef', b'ab/c/ef')
 
474
        self.assertCmpByDirs(-1, b'ab/cd/ef', b'ab/cd-ef')
 
475
        self.assertCmpByDirs(-1, b'ab/cd', b'ab/cd-')
 
476
        self.assertCmpByDirs(-1, b'ab/cd', b'ab-cd')
493
477
 
494
478
    def test_cmp_unicode_not_allowed(self):
495
 
        cmp_by_dirs = self.get_cmp_by_dirs()
496
 
        self.assertRaises(TypeError, cmp_by_dirs, u'Unicode', 'str')
497
 
        self.assertRaises(TypeError, cmp_by_dirs, 'str', u'Unicode')
498
 
        self.assertRaises(TypeError, cmp_by_dirs, u'Unicode', u'Unicode')
 
479
        lt_by_dirs = self.get_lt_by_dirs()
 
480
        self.assertRaises(TypeError, lt_by_dirs, u'Unicode', b'str')
 
481
        self.assertRaises(TypeError, lt_by_dirs, b'str', u'Unicode')
 
482
        self.assertRaises(TypeError, lt_by_dirs, u'Unicode', u'Unicode')
499
483
 
500
484
    def test_cmp_non_ascii(self):
501
 
        self.assertCmpByDirs(-1, '\xc2\xb5', '\xc3\xa5') # u'\xb5', u'\xe5'
502
 
        self.assertCmpByDirs(-1, 'a', '\xc3\xa5') # u'a', u'\xe5'
503
 
        self.assertCmpByDirs(-1, 'b', '\xc2\xb5') # u'b', u'\xb5'
504
 
        self.assertCmpByDirs(-1, 'a/b', 'a/\xc3\xa5') # u'a/b', u'a/\xe5'
505
 
        self.assertCmpByDirs(-1, 'b/a', 'b/\xc2\xb5') # u'b/a', u'b/\xb5'
506
 
 
507
 
 
508
 
class TestCompiledCmpByDirs(TestCmpByDirs):
509
 
    """Test the pyrex implementation of cmp_by_dirs"""
 
485
        self.assertCmpByDirs(-1, b'\xc2\xb5', b'\xc3\xa5') # u'\xb5', u'\xe5'
 
486
        self.assertCmpByDirs(-1, b'a', b'\xc3\xa5') # u'a', u'\xe5'
 
487
        self.assertCmpByDirs(-1, b'b', b'\xc2\xb5') # u'b', u'\xb5'
 
488
        self.assertCmpByDirs(-1, b'a/b', b'a/\xc3\xa5') # u'a/b', u'a/\xe5'
 
489
        self.assertCmpByDirs(-1, b'b/a', b'b/\xc2\xb5') # u'b/a', u'b/\xb5'
 
490
 
 
491
 
 
492
class TestCompiledLtByDirs(TestLtByDirs):
 
493
    """Test the pyrex implementation of lt_by_dirs"""
510
494
 
511
495
    _test_needs_features = [compiled_dirstate_helpers_feature]
512
496
 
513
 
    def get_cmp_by_dirs(self):
514
 
        from bzrlib._dirstate_helpers_pyx import cmp_by_dirs
515
 
        return cmp_by_dirs
516
 
 
517
 
 
518
 
class TestCmpPathByDirblock(tests.TestCase):
519
 
    """Test an implementation of _cmp_path_by_dirblock()
520
 
 
521
 
    _cmp_path_by_dirblock() compares two paths using the sort order used by
 
497
    def get_lt_by_dirs(self):
 
498
        from ..bzr._dirstate_helpers_pyx import lt_by_dirs
 
499
        return lt_by_dirs
 
500
 
 
501
 
 
502
class TestLtPathByDirblock(tests.TestCase):
 
503
    """Test an implementation of _lt_path_by_dirblock()
 
504
 
 
505
    _lt_path_by_dirblock() compares two paths using the sort order used by
522
506
    DirState. All paths in the same directory are sorted together.
523
507
 
524
 
    Child test cases can override ``get_cmp_path_by_dirblock`` to test a specific
 
508
    Child test cases can override ``get_lt_path_by_dirblock`` to test a specific
525
509
    implementation.
526
510
    """
527
511
 
528
 
    def get_cmp_path_by_dirblock(self):
529
 
        """Get a specific implementation of _cmp_path_by_dirblock."""
530
 
        from bzrlib._dirstate_helpers_py import _cmp_path_by_dirblock
531
 
        return _cmp_path_by_dirblock
 
512
    def get_lt_path_by_dirblock(self):
 
513
        """Get a specific implementation of _lt_path_by_dirblock."""
 
514
        from ..bzr._dirstate_helpers_py import _lt_path_by_dirblock
 
515
        return _lt_path_by_dirblock
532
516
 
533
 
    def assertCmpPathByDirblock(self, paths):
 
517
    def assertLtPathByDirblock(self, paths):
534
518
        """Compare all paths and make sure they evaluate to the correct order.
535
519
 
536
520
        This does N^2 comparisons. It is assumed that ``paths`` is properly
541
525
        # First, make sure the paths being passed in are correct
542
526
        def _key(p):
543
527
            dirname, basename = os.path.split(p)
544
 
            return dirname.split('/'), basename
 
528
            return dirname.split(b'/'), basename
545
529
        self.assertEqual(sorted(paths, key=_key), paths)
546
530
 
547
 
        cmp_path_by_dirblock = self.get_cmp_path_by_dirblock()
 
531
        lt_path_by_dirblock = self.get_lt_path_by_dirblock()
548
532
        for idx1, path1 in enumerate(paths):
549
533
            for idx2, path2 in enumerate(paths):
550
 
                cmp_val = cmp_path_by_dirblock(path1, path2)
551
 
                if idx1 < idx2:
552
 
                    self.assertTrue(cmp_val < 0,
553
 
                        '%s did not state that %r came before %r, cmp=%s'
554
 
                        % (cmp_path_by_dirblock.__name__,
555
 
                           path1, path2, cmp_val))
556
 
                elif idx1 > idx2:
557
 
                    self.assertTrue(cmp_val > 0,
558
 
                        '%s did not state that %r came after %r, cmp=%s'
559
 
                        % (cmp_path_by_dirblock.__name__,
560
 
                           path1, path2, cmp_val))
561
 
                else: # idx1 == idx2
562
 
                    self.assertTrue(cmp_val == 0,
563
 
                        '%s did not state that %r == %r, cmp=%s'
564
 
                        % (cmp_path_by_dirblock.__name__,
565
 
                           path1, path2, cmp_val))
 
534
                lt_result = lt_path_by_dirblock(path1, path2)
 
535
                self.assertEqual(idx1 < idx2, lt_result,
 
536
                        '%s did not state that %r < %r, lt=%s'
 
537
                        % (lt_path_by_dirblock.__name__,
 
538
                           path1, path2, lt_result))
566
539
 
567
540
    def test_cmp_simple_paths(self):
568
541
        """Compare against the empty string."""
569
 
        self.assertCmpPathByDirblock(['', 'a', 'ab', 'abc', 'a/b/c', 'b/d/e'])
570
 
        self.assertCmpPathByDirblock(['kl', 'ab/cd', 'ab/ef', 'gh/ij'])
 
542
        self.assertLtPathByDirblock([b'', b'a', b'ab', b'abc', b'a/b/c', b'b/d/e'])
 
543
        self.assertLtPathByDirblock([b'kl', b'ab/cd', b'ab/ef', b'gh/ij'])
571
544
 
572
545
    def test_tricky_paths(self):
573
 
        self.assertCmpPathByDirblock([
 
546
        self.assertLtPathByDirblock([
574
547
            # Contents of ''
575
 
            '', 'a', 'a-a', 'a=a', 'b',
 
548
            b'', b'a', b'a-a', b'a=a', b'b',
576
549
            # Contents of 'a'
577
 
            'a/a', 'a/a-a', 'a/a=a', 'a/b',
 
550
            b'a/a', b'a/a-a', b'a/a=a', b'a/b',
578
551
            # Contents of 'a/a'
579
 
            'a/a/a', 'a/a/a-a', 'a/a/a=a',
 
552
            b'a/a/a', b'a/a/a-a', b'a/a/a=a',
580
553
            # Contents of 'a/a/a'
581
 
            'a/a/a/a', 'a/a/a/b',
 
554
            b'a/a/a/a', b'a/a/a/b',
582
555
            # Contents of 'a/a/a-a',
583
 
            'a/a/a-a/a', 'a/a/a-a/b',
 
556
            b'a/a/a-a/a', b'a/a/a-a/b',
584
557
            # Contents of 'a/a/a=a',
585
 
            'a/a/a=a/a', 'a/a/a=a/b',
 
558
            b'a/a/a=a/a', b'a/a/a=a/b',
586
559
            # Contents of 'a/a-a'
587
 
            'a/a-a/a',
 
560
            b'a/a-a/a',
588
561
            # Contents of 'a/a-a/a'
589
 
            'a/a-a/a/a', 'a/a-a/a/b',
 
562
            b'a/a-a/a/a', b'a/a-a/a/b',
590
563
            # Contents of 'a/a=a'
591
 
            'a/a=a/a',
 
564
            b'a/a=a/a',
592
565
            # Contents of 'a/b'
593
 
            'a/b/a', 'a/b/b',
 
566
            b'a/b/a', b'a/b/b',
594
567
            # Contents of 'a-a',
595
 
            'a-a/a', 'a-a/b',
 
568
            b'a-a/a', b'a-a/b',
596
569
            # Contents of 'a=a',
597
 
            'a=a/a', 'a=a/b',
 
570
            b'a=a/a', b'a=a/b',
598
571
            # Contents of 'b',
599
 
            'b/a', 'b/b',
 
572
            b'b/a', b'b/b',
600
573
            ])
601
 
        self.assertCmpPathByDirblock([
 
574
        self.assertLtPathByDirblock([
602
575
                 # content of '/'
603
 
                 '', 'a', 'a-a', 'a-z', 'a=a', 'a=z',
 
576
                 b'', b'a', b'a-a', b'a-z', b'a=a', b'a=z',
604
577
                 # content of 'a/'
605
 
                 'a/a', 'a/a-a', 'a/a-z',
606
 
                 'a/a=a', 'a/a=z',
607
 
                 'a/z', 'a/z-a', 'a/z-z',
608
 
                 'a/z=a', 'a/z=z',
 
578
                 b'a/a', b'a/a-a', b'a/a-z',
 
579
                 b'a/a=a', b'a/a=z',
 
580
                 b'a/z', b'a/z-a', b'a/z-z',
 
581
                 b'a/z=a', b'a/z=z',
609
582
                 # content of 'a/a/'
610
 
                 'a/a/a', 'a/a/z',
 
583
                 b'a/a/a', b'a/a/z',
611
584
                 # content of 'a/a-a'
612
 
                 'a/a-a/a',
 
585
                 b'a/a-a/a',
613
586
                 # content of 'a/a-z'
614
 
                 'a/a-z/z',
 
587
                 b'a/a-z/z',
615
588
                 # content of 'a/a=a'
616
 
                 'a/a=a/a',
 
589
                 b'a/a=a/a',
617
590
                 # content of 'a/a=z'
618
 
                 'a/a=z/z',
 
591
                 b'a/a=z/z',
619
592
                 # content of 'a/z/'
620
 
                 'a/z/a', 'a/z/z',
 
593
                 b'a/z/a', b'a/z/z',
621
594
                 # content of 'a-a'
622
 
                 'a-a/a',
 
595
                 b'a-a/a',
623
596
                 # content of 'a-z'
624
 
                 'a-z/z',
 
597
                 b'a-z/z',
625
598
                 # content of 'a=a'
626
 
                 'a=a/a',
 
599
                 b'a=a/a',
627
600
                 # content of 'a=z'
628
 
                 'a=z/z',
 
601
                 b'a=z/z',
629
602
                ])
630
603
 
631
604
    def test_unicode_not_allowed(self):
632
 
        cmp_path_by_dirblock = self.get_cmp_path_by_dirblock()
633
 
        self.assertRaises(TypeError, cmp_path_by_dirblock, u'Uni', 'str')
634
 
        self.assertRaises(TypeError, cmp_path_by_dirblock, 'str', u'Uni')
635
 
        self.assertRaises(TypeError, cmp_path_by_dirblock, u'Uni', u'Uni')
636
 
        self.assertRaises(TypeError, cmp_path_by_dirblock, u'x/Uni', 'x/str')
637
 
        self.assertRaises(TypeError, cmp_path_by_dirblock, 'x/str', u'x/Uni')
638
 
        self.assertRaises(TypeError, cmp_path_by_dirblock, u'x/Uni', u'x/Uni')
 
605
        lt_path_by_dirblock = self.get_lt_path_by_dirblock()
 
606
        self.assertRaises(TypeError, lt_path_by_dirblock, u'Uni', 'str')
 
607
        self.assertRaises(TypeError, lt_path_by_dirblock, 'str', u'Uni')
 
608
        self.assertRaises(TypeError, lt_path_by_dirblock, u'Uni', u'Uni')
 
609
        self.assertRaises(TypeError, lt_path_by_dirblock, u'x/Uni', 'x/str')
 
610
        self.assertRaises(TypeError, lt_path_by_dirblock, 'x/str', u'x/Uni')
 
611
        self.assertRaises(TypeError, lt_path_by_dirblock, u'x/Uni', u'x/Uni')
639
612
 
640
613
    def test_nonascii(self):
641
 
        self.assertCmpPathByDirblock([
 
614
        self.assertLtPathByDirblock([
642
615
            # content of '/'
643
 
            '', 'a', '\xc2\xb5', '\xc3\xa5',
 
616
            b'', b'a', b'\xc2\xb5', b'\xc3\xa5',
644
617
            # content of 'a'
645
 
            'a/a', 'a/\xc2\xb5', 'a/\xc3\xa5',
 
618
            b'a/a', b'a/\xc2\xb5', b'a/\xc3\xa5',
646
619
            # content of 'a/a'
647
 
            'a/a/a', 'a/a/\xc2\xb5', 'a/a/\xc3\xa5',
 
620
            b'a/a/a', b'a/a/\xc2\xb5', b'a/a/\xc3\xa5',
648
621
            # content of 'a/\xc2\xb5'
649
 
            'a/\xc2\xb5/a', 'a/\xc2\xb5/\xc2\xb5', 'a/\xc2\xb5/\xc3\xa5',
 
622
            b'a/\xc2\xb5/a', b'a/\xc2\xb5/\xc2\xb5', b'a/\xc2\xb5/\xc3\xa5',
650
623
            # content of 'a/\xc3\xa5'
651
 
            'a/\xc3\xa5/a', 'a/\xc3\xa5/\xc2\xb5', 'a/\xc3\xa5/\xc3\xa5',
 
624
            b'a/\xc3\xa5/a', b'a/\xc3\xa5/\xc2\xb5', b'a/\xc3\xa5/\xc3\xa5',
652
625
            # content of '\xc2\xb5'
653
 
            '\xc2\xb5/a', '\xc2\xb5/\xc2\xb5', '\xc2\xb5/\xc3\xa5',
 
626
            b'\xc2\xb5/a', b'\xc2\xb5/\xc2\xb5', b'\xc2\xb5/\xc3\xa5',
654
627
            # content of '\xc2\xe5'
655
 
            '\xc3\xa5/a', '\xc3\xa5/\xc2\xb5', '\xc3\xa5/\xc3\xa5',
 
628
            b'\xc3\xa5/a', b'\xc3\xa5/\xc2\xb5', b'\xc3\xa5/\xc3\xa5',
656
629
            ])
657
630
 
658
631
 
659
 
class TestCompiledCmpPathByDirblock(TestCmpPathByDirblock):
660
 
    """Test the pyrex implementation of _cmp_path_by_dirblock"""
 
632
class TestCompiledLtPathByDirblock(TestLtPathByDirblock):
 
633
    """Test the pyrex implementation of _lt_path_by_dirblock"""
661
634
 
662
635
    _test_needs_features = [compiled_dirstate_helpers_feature]
663
636
 
664
 
    def get_cmp_by_dirs(self):
665
 
        from bzrlib._dirstate_helpers_pyx import _cmp_path_by_dirblock
666
 
        return _cmp_path_by_dirblock
 
637
    def get_lt_path_by_dirblock(self):
 
638
        from ..bzr._dirstate_helpers_pyx import _lt_path_by_dirblock
 
639
        return _lt_path_by_dirblock
667
640
 
668
641
 
669
642
class TestMemRChr(tests.TestCase):
672
645
    _test_needs_features = [compiled_dirstate_helpers_feature]
673
646
 
674
647
    def assertMemRChr(self, expected, s, c):
675
 
        from bzrlib._dirstate_helpers_pyx import _py_memrchr
 
648
        from breezy.bzr._dirstate_helpers_pyx import _py_memrchr
676
649
        self.assertEqual(expected, _py_memrchr(s, c))
677
650
 
678
651
    def test_missing(self):
719
692
    implementation.
720
693
    """
721
694
 
 
695
    # inherits scenarios from test_dirstate
 
696
 
722
697
    def get_read_dirblocks(self):
723
 
        from bzrlib._dirstate_helpers_py import _read_dirblocks
 
698
        from breezy.bzr._dirstate_helpers_py import _read_dirblocks
724
699
        return _read_dirblocks
725
700
 
726
701
    def test_smoketest(self):
737
712
 
738
713
    def test_trailing_garbage(self):
739
714
        tree, state, expected = self.create_basic_dirstate()
740
 
        # On Linux, we can write extra data as long as we haven't read yet, but
 
715
        # On Unix, we can write extra data as long as we haven't read yet, but
741
716
        # on Win32, if you've opened the file with FILE_SHARE_READ, trying to
742
717
        # open it in append mode will fail.
743
718
        state.unlock()
744
719
        f = open('dirstate', 'ab')
745
720
        try:
746
721
            # Add bogus trailing garbage
747
 
            f.write('bogus\n')
 
722
            f.write(b'bogus\n')
748
723
        finally:
749
724
            f.close()
750
725
            state.lock_read()
751
 
        e = self.assertRaises(errors.DirstateCorrupt,
 
726
        e = self.assertRaises(dirstate.DirstateCorrupt,
752
727
                              state._read_dirblocks_if_needed)
753
728
        # Make sure we mention the bogus characters in the error
754
729
        self.assertContainsRe(str(e), 'bogus')
760
735
    _test_needs_features = [compiled_dirstate_helpers_feature]
761
736
 
762
737
    def get_read_dirblocks(self):
763
 
        from bzrlib._dirstate_helpers_pyx import _read_dirblocks
 
738
        from breezy.bzr._dirstate_helpers_pyx import _read_dirblocks
764
739
        return _read_dirblocks
765
740
 
766
741
 
774
749
 
775
750
    def test_bisect_dirblock(self):
776
751
        if compiled_dirstate_helpers_feature.available():
777
 
            from bzrlib._dirstate_helpers_pyx import bisect_dirblock
 
752
            from breezy.bzr._dirstate_helpers_pyx import bisect_dirblock
778
753
        else:
779
 
            from bzrlib._dirstate_helpers_py import bisect_dirblock
 
754
            from breezy.bzr._dirstate_helpers_py import bisect_dirblock
780
755
        self.assertIs(bisect_dirblock, dirstate.bisect_dirblock)
781
756
 
782
757
    def test__bisect_path_left(self):
783
758
        if compiled_dirstate_helpers_feature.available():
784
 
            from bzrlib._dirstate_helpers_pyx import _bisect_path_left
 
759
            from breezy.bzr._dirstate_helpers_pyx import _bisect_path_left
785
760
        else:
786
 
            from bzrlib._dirstate_helpers_py import _bisect_path_left
 
761
            from breezy.bzr._dirstate_helpers_py import _bisect_path_left
787
762
        self.assertIs(_bisect_path_left, dirstate._bisect_path_left)
788
763
 
789
764
    def test__bisect_path_right(self):
790
765
        if compiled_dirstate_helpers_feature.available():
791
 
            from bzrlib._dirstate_helpers_pyx import _bisect_path_right
 
766
            from breezy.bzr._dirstate_helpers_pyx import _bisect_path_right
792
767
        else:
793
 
            from bzrlib._dirstate_helpers_py import _bisect_path_right
 
768
            from breezy.bzr._dirstate_helpers_py import _bisect_path_right
794
769
        self.assertIs(_bisect_path_right, dirstate._bisect_path_right)
795
770
 
796
 
    def test_cmp_by_dirs(self):
 
771
    def test_lt_by_dirs(self):
797
772
        if compiled_dirstate_helpers_feature.available():
798
 
            from bzrlib._dirstate_helpers_pyx import cmp_by_dirs
 
773
            from ..bzr._dirstate_helpers_pyx import lt_by_dirs
799
774
        else:
800
 
            from bzrlib._dirstate_helpers_py import cmp_by_dirs
801
 
        self.assertIs(cmp_by_dirs, dirstate.cmp_by_dirs)
 
775
            from ..bzr._dirstate_helpers_py import lt_by_dirs
 
776
        self.assertIs(lt_by_dirs, dirstate.lt_by_dirs)
802
777
 
803
778
    def test__read_dirblocks(self):
804
779
        if compiled_dirstate_helpers_feature.available():
805
 
            from bzrlib._dirstate_helpers_pyx import _read_dirblocks
 
780
            from breezy.bzr._dirstate_helpers_pyx import _read_dirblocks
806
781
        else:
807
 
            from bzrlib._dirstate_helpers_py import _read_dirblocks
 
782
            from breezy.bzr._dirstate_helpers_py import _read_dirblocks
808
783
        self.assertIs(_read_dirblocks, dirstate._read_dirblocks)
809
784
 
810
785
    def test_update_entry(self):
811
786
        if compiled_dirstate_helpers_feature.available():
812
 
            from bzrlib._dirstate_helpers_pyx import update_entry
 
787
            from breezy.bzr._dirstate_helpers_pyx import update_entry
813
788
        else:
814
 
            from bzrlib.dirstate import update_entry
 
789
            from breezy.bzr.dirstate import update_entry
815
790
        self.assertIs(update_entry, dirstate.update_entry)
816
791
 
817
792
    def test_process_entry(self):
818
793
        if compiled_dirstate_helpers_feature.available():
819
 
            from bzrlib._dirstate_helpers_pyx import ProcessEntryC
 
794
            from breezy.bzr._dirstate_helpers_pyx import ProcessEntryC
820
795
            self.assertIs(ProcessEntryC, dirstate._process_entry)
821
796
        else:
822
 
            from bzrlib.dirstate import ProcessEntryPython
 
797
            from breezy.bzr.dirstate import ProcessEntryPython
823
798
            self.assertIs(ProcessEntryPython, dirstate._process_entry)
824
799
 
825
800
 
826
801
class TestUpdateEntry(test_dirstate.TestCaseWithDirState):
827
802
    """Test the DirState.update_entry functions"""
828
803
 
 
804
    scenarios = multiply_scenarios(
 
805
        dir_reader_scenarios(), ue_scenarios)
 
806
 
829
807
    # Set by load_tests
830
808
    update_entry = None
831
809
 
837
815
        """Create a DirState tracking a single object named 'a'"""
838
816
        state = test_dirstate.InstrumentedDirState.initialize('dirstate')
839
817
        self.addCleanup(state.unlock)
840
 
        state.add('a', 'a-id', 'file', None, '')
841
 
        entry = state._get_entry(0, path_utf8='a')
 
818
        state.add('a', b'a-id', 'file', None, b'')
 
819
        entry = state._get_entry(0, path_utf8=b'a')
842
820
        return state, entry
843
821
 
844
822
    def test_observed_sha1_cachable(self):
845
823
        state, entry = self.get_state_with_a()
 
824
        state.save()
846
825
        atime = time.time() - 10
847
826
        self.build_tree(['a'])
848
 
        statvalue = os.lstat('a')
849
 
        statvalue = test_dirstate._FakeStat(statvalue.st_size, atime, atime,
850
 
            statvalue.st_dev, statvalue.st_ino, statvalue.st_mode)
851
 
        state._observed_sha1(entry, "foo", statvalue)
852
 
        self.assertEqual('foo', entry[1][0][1])
 
827
        statvalue = test_dirstate._FakeStat.from_stat(os.lstat('a'))
 
828
        statvalue.st_mtime = statvalue.st_ctime = atime
 
829
        self.assertEqual(dirstate.DirState.IN_MEMORY_UNMODIFIED,
 
830
                         state._dirblock_state)
 
831
        state._observed_sha1(entry, b"foo", statvalue)
 
832
        self.assertEqual(b'foo', entry[1][0][1])
853
833
        packed_stat = dirstate.pack_stat(statvalue)
854
834
        self.assertEqual(packed_stat, entry[1][0][4])
 
835
        self.assertEqual(dirstate.DirState.IN_MEMORY_HASH_MODIFIED,
 
836
                         state._dirblock_state)
855
837
 
856
838
    def test_observed_sha1_not_cachable(self):
857
839
        state, entry = self.get_state_with_a()
 
840
        state.save()
858
841
        oldval = entry[1][0][1]
859
842
        oldstat = entry[1][0][4]
860
843
        self.build_tree(['a'])
861
844
        statvalue = os.lstat('a')
 
845
        self.assertEqual(dirstate.DirState.IN_MEMORY_UNMODIFIED,
 
846
                         state._dirblock_state)
862
847
        state._observed_sha1(entry, "foo", statvalue)
863
848
        self.assertEqual(oldval, entry[1][0][1])
864
849
        self.assertEqual(oldstat, entry[1][0][4])
 
850
        self.assertEqual(dirstate.DirState.IN_MEMORY_UNMODIFIED,
 
851
                         state._dirblock_state)
865
852
 
866
853
    def test_update_entry(self):
867
854
        state, _ = self.get_state_with_a()
869
856
        tree.lock_write()
870
857
        empty_revid = tree.commit('empty')
871
858
        self.build_tree(['tree/a'])
872
 
        tree.add(['a'], ['a-id'])
 
859
        tree.add(['a'], [b'a-id'])
873
860
        with_a_id = tree.commit('with_a')
874
861
        self.addCleanup(tree.unlock)
875
862
        state.set_parent_trees(
876
863
            [(empty_revid, tree.branch.repository.revision_tree(empty_revid))],
877
864
            [])
878
 
        entry = state._get_entry(0, path_utf8='a')
 
865
        entry = state._get_entry(0, path_utf8=b'a')
879
866
        self.build_tree(['a'])
880
867
        # Add one where we don't provide the stat or sha already
881
 
        self.assertEqual(('', 'a', 'a-id'), entry[0])
882
 
        self.assertEqual(('f', '', 0, False, dirstate.DirState.NULLSTAT),
 
868
        self.assertEqual((b'', b'a', b'a-id'), entry[0])
 
869
        self.assertEqual((b'f', b'', 0, False, dirstate.DirState.NULLSTAT),
883
870
                         entry[1][0])
884
871
        # Flush the buffers to disk
885
872
        state.save()
888
875
 
889
876
        stat_value = os.lstat('a')
890
877
        packed_stat = dirstate.pack_stat(stat_value)
891
 
        link_or_sha1 = self.update_entry(state, entry, abspath='a',
 
878
        link_or_sha1 = self.update_entry(state, entry, abspath=b'a',
892
879
                                          stat_value=stat_value)
893
880
        self.assertEqual(None, link_or_sha1)
894
881
 
895
 
        # The dirblock entry should not have cached the file's sha1 (too new)
896
 
        self.assertEqual(('f', '', 14, False, dirstate.DirState.NULLSTAT),
 
882
        # The dirblock entry should not have computed or cached the file's
 
883
        # sha1, but it did update the files' st_size. However, this is not
 
884
        # worth writing a dirstate file for, so we leave the state UNMODIFIED
 
885
        self.assertEqual((b'f', b'', 14, False, dirstate.DirState.NULLSTAT),
897
886
                         entry[1][0])
898
 
        self.assertEqual(dirstate.DirState.IN_MEMORY_MODIFIED,
 
887
        self.assertEqual(dirstate.DirState.IN_MEMORY_UNMODIFIED,
899
888
                         state._dirblock_state)
900
889
        mode = stat_value.st_mode
901
890
        self.assertEqual([('is_exec', mode, False)], state._log)
904
893
        self.assertEqual(dirstate.DirState.IN_MEMORY_UNMODIFIED,
905
894
                         state._dirblock_state)
906
895
 
907
 
        # If we do it again right away, we don't know if the file has changed
908
 
        # so we will re-read the file. Roll the clock back so the file is
909
 
        # guaranteed to look too new.
 
896
        # Roll the clock back so the file is guaranteed to look too new. We
 
897
        # should still not compute the sha1.
910
898
        state.adjust_time(-10)
911
899
        del state._log[:]
912
900
 
913
 
        link_or_sha1 = self.update_entry(state, entry, abspath='a',
 
901
        link_or_sha1 = self.update_entry(state, entry, abspath=b'a',
914
902
                                          stat_value=stat_value)
915
903
        self.assertEqual([('is_exec', mode, False)], state._log)
916
904
        self.assertEqual(None, link_or_sha1)
917
 
        self.assertEqual(dirstate.DirState.IN_MEMORY_MODIFIED,
 
905
        self.assertEqual(dirstate.DirState.IN_MEMORY_UNMODIFIED,
918
906
                         state._dirblock_state)
919
 
        self.assertEqual(('f', '', 14, False, dirstate.DirState.NULLSTAT),
 
907
        self.assertEqual((b'f', b'', 14, False, dirstate.DirState.NULLSTAT),
920
908
                         entry[1][0])
921
909
        state.save()
922
910
 
924
912
        # won't calculate the sha or cache it.
925
913
        state.adjust_time(+20)
926
914
        del state._log[:]
927
 
        link_or_sha1 = dirstate.update_entry(state, entry, abspath='a',
 
915
        link_or_sha1 = dirstate.update_entry(state, entry, abspath=b'a',
928
916
                                          stat_value=stat_value)
929
917
        self.assertEqual(None, link_or_sha1)
930
918
        self.assertEqual([('is_exec', mode, False)], state._log)
931
 
        self.assertEqual(('f', '', 14, False, dirstate.DirState.NULLSTAT),
 
919
        self.assertEqual((b'f', b'', 14, False, dirstate.DirState.NULLSTAT),
932
920
                         entry[1][0])
 
921
        self.assertEqual(dirstate.DirState.IN_MEMORY_UNMODIFIED,
 
922
                         state._dirblock_state)
933
923
 
934
924
        # If the file is no longer new, and the clock has been moved forward
935
925
        # sufficiently, it will cache the sha.
937
927
        state.set_parent_trees(
938
928
            [(with_a_id, tree.branch.repository.revision_tree(with_a_id))],
939
929
            [])
940
 
        entry = state._get_entry(0, path_utf8='a')
 
930
        entry = state._get_entry(0, path_utf8=b'a')
941
931
 
942
 
        link_or_sha1 = self.update_entry(state, entry, abspath='a',
 
932
        link_or_sha1 = self.update_entry(state, entry, abspath=b'a',
943
933
                                          stat_value=stat_value)
944
 
        self.assertEqual('b50e5406bb5e153ebbeb20268fcf37c87e1ecfb6',
 
934
        self.assertEqual(b'b50e5406bb5e153ebbeb20268fcf37c87e1ecfb6',
945
935
                         link_or_sha1)
946
 
        self.assertEqual([('is_exec', mode, False), ('sha1', 'a')],
 
936
        self.assertEqual([('is_exec', mode, False), ('sha1', b'a')],
947
937
                          state._log)
948
 
        self.assertEqual(('f', link_or_sha1, 14, False, packed_stat),
 
938
        self.assertEqual((b'f', link_or_sha1, 14, False, packed_stat),
949
939
                         entry[1][0])
950
940
 
951
941
        # Subsequent calls will just return the cached value
952
942
        del state._log[:]
953
 
        link_or_sha1 = self.update_entry(state, entry, abspath='a',
 
943
        link_or_sha1 = self.update_entry(state, entry, abspath=b'a',
954
944
                                          stat_value=stat_value)
955
 
        self.assertEqual('b50e5406bb5e153ebbeb20268fcf37c87e1ecfb6',
 
945
        self.assertEqual(b'b50e5406bb5e153ebbeb20268fcf37c87e1ecfb6',
956
946
                         link_or_sha1)
957
947
        self.assertEqual([], state._log)
958
 
        self.assertEqual(('f', link_or_sha1, 14, False, packed_stat),
 
948
        self.assertEqual((b'f', link_or_sha1, 14, False, packed_stat),
959
949
                         entry[1][0])
960
950
 
961
951
    def test_update_entry_symlink(self):
962
952
        """Update entry should read symlinks."""
963
 
        self.requireFeature(tests.SymlinkFeature)
 
953
        self.requireFeature(features.SymlinkFeature)
964
954
        state, entry = self.get_state_with_a()
965
955
        state.save()
966
956
        self.assertEqual(dirstate.DirState.IN_MEMORY_UNMODIFIED,
970
960
        state.adjust_time(-10) # Make the symlink look new
971
961
        stat_value = os.lstat('a')
972
962
        packed_stat = dirstate.pack_stat(stat_value)
973
 
        link_or_sha1 = self.update_entry(state, entry, abspath='a',
 
963
        link_or_sha1 = self.update_entry(state, entry, abspath=b'a',
974
964
                                          stat_value=stat_value)
975
 
        self.assertEqual('target', link_or_sha1)
976
 
        self.assertEqual([('read_link', 'a', '')], state._log)
 
965
        self.assertEqual(b'target', link_or_sha1)
 
966
        self.assertEqual([('read_link', b'a', b'')], state._log)
977
967
        # Dirblock is not updated (the link is too new)
978
 
        self.assertEqual([('l', '', 6, False, dirstate.DirState.NULLSTAT)],
 
968
        self.assertEqual([(b'l', b'', 6, False, dirstate.DirState.NULLSTAT)],
979
969
                         entry[1])
980
 
        self.assertEqual(dirstate.DirState.IN_MEMORY_MODIFIED,
 
970
        # The file entry turned into a symlink, that is considered
 
971
        # HASH modified worthy.
 
972
        self.assertEqual(dirstate.DirState.IN_MEMORY_HASH_MODIFIED,
981
973
                         state._dirblock_state)
982
974
 
983
975
        # Because the stat_value looks new, we should re-read the target
984
 
        link_or_sha1 = self.update_entry(state, entry, abspath='a',
 
976
        del state._log[:]
 
977
        link_or_sha1 = self.update_entry(state, entry, abspath=b'a',
985
978
                                          stat_value=stat_value)
986
 
        self.assertEqual('target', link_or_sha1)
987
 
        self.assertEqual([('read_link', 'a', ''),
988
 
                          ('read_link', 'a', ''),
989
 
                         ], state._log)
990
 
        self.assertEqual([('l', '', 6, False, dirstate.DirState.NULLSTAT)],
 
979
        self.assertEqual(b'target', link_or_sha1)
 
980
        self.assertEqual([('read_link', b'a', b'')], state._log)
 
981
        self.assertEqual([(b'l', b'', 6, False, dirstate.DirState.NULLSTAT)],
991
982
                         entry[1])
 
983
        state.save()
992
984
        state.adjust_time(+20) # Skip into the future, all files look old
993
 
        link_or_sha1 = self.update_entry(state, entry, abspath='a',
 
985
        del state._log[:]
 
986
        link_or_sha1 = self.update_entry(state, entry, abspath=b'a',
994
987
                                          stat_value=stat_value)
995
 
        self.assertEqual('target', link_or_sha1)
 
988
        # The symlink stayed a symlink. So while it is new enough to cache, we
 
989
        # don't bother setting the flag, because it is not really worth saving
 
990
        # (when we stat the symlink, we'll have paged in the target.)
 
991
        self.assertEqual(dirstate.DirState.IN_MEMORY_UNMODIFIED,
 
992
                         state._dirblock_state)
 
993
        self.assertEqual(b'target', link_or_sha1)
996
994
        # We need to re-read the link because only now can we cache it
997
 
        self.assertEqual([('read_link', 'a', ''),
998
 
                          ('read_link', 'a', ''),
999
 
                          ('read_link', 'a', ''),
1000
 
                         ], state._log)
1001
 
        self.assertEqual([('l', 'target', 6, False, packed_stat)],
 
995
        self.assertEqual([('read_link', b'a', b'')], state._log)
 
996
        self.assertEqual([(b'l', b'target', 6, False, packed_stat)],
1002
997
                         entry[1])
1003
998
 
 
999
        del state._log[:]
1004
1000
        # Another call won't re-read the link
1005
 
        self.assertEqual([('read_link', 'a', ''),
1006
 
                          ('read_link', 'a', ''),
1007
 
                          ('read_link', 'a', ''),
1008
 
                         ], state._log)
1009
 
        link_or_sha1 = self.update_entry(state, entry, abspath='a',
 
1001
        self.assertEqual([], state._log)
 
1002
        link_or_sha1 = self.update_entry(state, entry, abspath=b'a',
1010
1003
                                          stat_value=stat_value)
1011
 
        self.assertEqual('target', link_or_sha1)
1012
 
        self.assertEqual([('l', 'target', 6, False, packed_stat)],
 
1004
        self.assertEqual(b'target', link_or_sha1)
 
1005
        self.assertEqual([(b'l', b'target', 6, False, packed_stat)],
1013
1006
                         entry[1])
1014
1007
 
1015
1008
    def do_update_entry(self, state, entry, abspath):
1019
1012
    def test_update_entry_dir(self):
1020
1013
        state, entry = self.get_state_with_a()
1021
1014
        self.build_tree(['a/'])
1022
 
        self.assertIs(None, self.do_update_entry(state, entry, 'a'))
 
1015
        self.assertIs(None, self.do_update_entry(state, entry, b'a'))
1023
1016
 
1024
1017
    def test_update_entry_dir_unchanged(self):
1025
1018
        state, entry = self.get_state_with_a()
1026
1019
        self.build_tree(['a/'])
1027
1020
        state.adjust_time(+20)
1028
 
        self.assertIs(None, self.do_update_entry(state, entry, 'a'))
 
1021
        self.assertIs(None, self.do_update_entry(state, entry, b'a'))
 
1022
        # a/ used to be a file, but is now a directory, worth saving
1029
1023
        self.assertEqual(dirstate.DirState.IN_MEMORY_MODIFIED,
1030
1024
                         state._dirblock_state)
1031
1025
        state.save()
1032
1026
        self.assertEqual(dirstate.DirState.IN_MEMORY_UNMODIFIED,
1033
1027
                         state._dirblock_state)
1034
 
        self.assertIs(None, self.do_update_entry(state, entry, 'a'))
 
1028
        # No changes to a/ means not worth saving.
 
1029
        self.assertIs(None, self.do_update_entry(state, entry, b'a'))
 
1030
        self.assertEqual(dirstate.DirState.IN_MEMORY_UNMODIFIED,
 
1031
                         state._dirblock_state)
 
1032
        # Change the last-modified time for the directory
 
1033
        t = time.time() - 100.0
 
1034
        try:
 
1035
            os.utime('a', (t, t))
 
1036
        except OSError:
 
1037
            # It looks like Win32 + FAT doesn't allow to change times on a dir.
 
1038
            raise tests.TestSkipped("can't update mtime of a dir on FAT")
 
1039
        saved_packed_stat = entry[1][0][-1]
 
1040
        self.assertIs(None, self.do_update_entry(state, entry, b'a'))
 
1041
        # We *do* go ahead and update the information in the dirblocks, but we
 
1042
        # don't bother setting IN_MEMORY_MODIFIED because it is trivial to
 
1043
        # recompute.
 
1044
        self.assertNotEqual(saved_packed_stat, entry[1][0][-1])
1035
1045
        self.assertEqual(dirstate.DirState.IN_MEMORY_UNMODIFIED,
1036
1046
                         state._dirblock_state)
1037
1047
 
1040
1050
        tree = self.make_branch_and_tree('tree')
1041
1051
        tree.lock_write()
1042
1052
        self.build_tree(['tree/a'])
1043
 
        tree.add(['a'], ['a-id'])
 
1053
        tree.add(['a'], [b'a-id'])
1044
1054
        with_a_id = tree.commit('witha')
1045
1055
        self.addCleanup(tree.unlock)
1046
1056
        state.set_parent_trees(
1047
1057
            [(with_a_id, tree.branch.repository.revision_tree(with_a_id))],
1048
1058
            [])
1049
 
        entry = state._get_entry(0, path_utf8='a')
 
1059
        entry = state._get_entry(0, path_utf8=b'a')
1050
1060
        self.build_tree(['a'])
1051
 
        sha1sum = 'b50e5406bb5e153ebbeb20268fcf37c87e1ecfb6'
 
1061
        sha1sum = b'b50e5406bb5e153ebbeb20268fcf37c87e1ecfb6'
1052
1062
        state.adjust_time(+20)
1053
 
        self.assertEqual(sha1sum, self.do_update_entry(state, entry, 'a'))
 
1063
        self.assertEqual(sha1sum, self.do_update_entry(state, entry, b'a'))
1054
1064
        self.assertEqual(dirstate.DirState.IN_MEMORY_MODIFIED,
1055
1065
                         state._dirblock_state)
1056
1066
        state.save()
1057
1067
        self.assertEqual(dirstate.DirState.IN_MEMORY_UNMODIFIED,
1058
1068
                         state._dirblock_state)
1059
 
        self.assertEqual(sha1sum, self.do_update_entry(state, entry, 'a'))
 
1069
        self.assertEqual(sha1sum, self.do_update_entry(state, entry, b'a'))
1060
1070
        self.assertEqual(dirstate.DirState.IN_MEMORY_UNMODIFIED,
1061
1071
                         state._dirblock_state)
1062
1072
 
1063
1073
    def test_update_entry_tree_reference(self):
1064
1074
        state = test_dirstate.InstrumentedDirState.initialize('dirstate')
1065
1075
        self.addCleanup(state.unlock)
1066
 
        state.add('r', 'r-id', 'tree-reference', None, '')
 
1076
        state.add('r', b'r-id', 'tree-reference', None, b'')
1067
1077
        self.build_tree(['r/'])
1068
 
        entry = state._get_entry(0, path_utf8='r')
 
1078
        entry = state._get_entry(0, path_utf8=b'r')
1069
1079
        self.do_update_entry(state, entry, 'r')
1070
 
        entry = state._get_entry(0, path_utf8='r')
1071
 
        self.assertEqual('t', entry[1][0][0])
 
1080
        entry = state._get_entry(0, path_utf8=b'r')
 
1081
        self.assertEqual(b't', entry[1][0][0])
1072
1082
 
1073
1083
    def create_and_test_file(self, state, entry):
1074
1084
        """Create a file at 'a' and verify the state finds it during update.
1082
1092
 
1083
1093
        link_or_sha1 = self.do_update_entry(state, entry, abspath='a')
1084
1094
        self.assertEqual(None, link_or_sha1)
1085
 
        self.assertEqual([('f', '', 14, False, dirstate.DirState.NULLSTAT)],
 
1095
        self.assertEqual([(b'f', b'', 14, False, dirstate.DirState.NULLSTAT)],
1086
1096
                         entry[1])
1087
1097
        return packed_stat
1088
1098
 
1096
1106
        stat_value = os.lstat('a')
1097
1107
        packed_stat = dirstate.pack_stat(stat_value)
1098
1108
 
1099
 
        link_or_sha1 = self.do_update_entry(state, entry, abspath='a')
 
1109
        link_or_sha1 = self.do_update_entry(state, entry, abspath=b'a')
1100
1110
        self.assertIs(None, link_or_sha1)
1101
 
        self.assertEqual([('d', '', 0, False, packed_stat)], entry[1])
 
1111
        self.assertEqual([(b'd', b'', 0, False, packed_stat)], entry[1])
1102
1112
 
1103
1113
        return packed_stat
1104
1114
 
1118
1128
        stat_value = os.lstat('a')
1119
1129
        packed_stat = dirstate.pack_stat(stat_value)
1120
1130
 
1121
 
        link_or_sha1 = self.do_update_entry(state, entry, abspath='a')
1122
 
        self.assertEqual('path/to/foo', link_or_sha1)
1123
 
        self.assertEqual([('l', 'path/to/foo', 11, False, packed_stat)],
 
1131
        link_or_sha1 = self.do_update_entry(state, entry, abspath=b'a')
 
1132
        self.assertEqual(b'path/to/foo', link_or_sha1)
 
1133
        self.assertEqual([(b'l', b'path/to/foo', 11, False, packed_stat)],
1124
1134
                         entry[1])
1125
1135
        return packed_stat
1126
1136
 
1137
1147
 
1138
1148
    def test_update_file_to_symlink(self):
1139
1149
        """File becomes a symlink"""
1140
 
        self.requireFeature(tests.SymlinkFeature)
 
1150
        self.requireFeature(features.SymlinkFeature)
1141
1151
        state, entry = self.get_state_with_a()
1142
1152
        # The file sha1 won't be cached unless the file is old
1143
1153
        state.adjust_time(+10)
1156
1166
 
1157
1167
    def test_update_dir_to_symlink(self):
1158
1168
        """Directory becomes a symlink"""
1159
 
        self.requireFeature(tests.SymlinkFeature)
 
1169
        self.requireFeature(features.SymlinkFeature)
1160
1170
        state, entry = self.get_state_with_a()
1161
1171
        # The symlink target won't be cached if it isn't old
1162
1172
        state.adjust_time(+10)
1166
1176
 
1167
1177
    def test_update_symlink_to_file(self):
1168
1178
        """Symlink becomes a file"""
1169
 
        self.requireFeature(tests.SymlinkFeature)
 
1179
        self.requireFeature(features.SymlinkFeature)
1170
1180
        state, entry = self.get_state_with_a()
1171
1181
        # The symlink and file info won't be cached unless old
1172
1182
        state.adjust_time(+10)
1176
1186
 
1177
1187
    def test_update_symlink_to_dir(self):
1178
1188
        """Symlink becomes a directory"""
1179
 
        self.requireFeature(tests.SymlinkFeature)
 
1189
        self.requireFeature(features.SymlinkFeature)
1180
1190
        state, entry = self.get_state_with_a()
1181
1191
        # The symlink target won't be cached if it isn't old
1182
1192
        state.adjust_time(+10)
1193
1203
 
1194
1204
        # The file on disk is not executable, but we are marking it as though
1195
1205
        # it is. With _is_executable_win32 we ignore what is on disk.
1196
 
        entry[1][0] = ('f', '', 0, True, dirstate.DirState.NULLSTAT)
 
1206
        entry[1][0] = (b'f', b'', 0, True, dirstate.DirState.NULLSTAT)
1197
1207
 
1198
1208
        stat_value = os.lstat('a')
1199
1209
        packed_stat = dirstate.pack_stat(stat_value)
1200
1210
 
1201
1211
        state.adjust_time(-10) # Make sure everything is new
1202
 
        self.update_entry(state, entry, abspath='a', stat_value=stat_value)
 
1212
        self.update_entry(state, entry, abspath=b'a', stat_value=stat_value)
1203
1213
 
1204
1214
        # The row is updated, but the executable bit stays set.
1205
 
        self.assertEqual([('f', '', 14, True, dirstate.DirState.NULLSTAT)],
 
1215
        self.assertEqual([(b'f', b'', 14, True, dirstate.DirState.NULLSTAT)],
1206
1216
                         entry[1])
1207
1217
 
1208
1218
        # Make the disk object look old enough to cache (but it won't cache the
1209
1219
        # sha as it is a new file).
1210
1220
        state.adjust_time(+20)
1211
 
        digest = 'b50e5406bb5e153ebbeb20268fcf37c87e1ecfb6'
1212
 
        self.update_entry(state, entry, abspath='a', stat_value=stat_value)
1213
 
        self.assertEqual([('f', '', 14, True, dirstate.DirState.NULLSTAT)],
 
1221
        digest = b'b50e5406bb5e153ebbeb20268fcf37c87e1ecfb6'
 
1222
        self.update_entry(state, entry, abspath=b'a', stat_value=stat_value)
 
1223
        self.assertEqual([(b'f', b'', 14, True, dirstate.DirState.NULLSTAT)],
1214
1224
            entry[1])
1215
1225
 
1216
1226
    def _prepare_tree(self):
1217
1227
        # Create a tree
1218
 
        text = 'Hello World\n'
 
1228
        text = b'Hello World\n'
1219
1229
        tree = self.make_branch_and_tree('tree')
1220
1230
        self.build_tree_contents([('tree/a file', text)])
1221
 
        tree.add('a file', 'a-file-id')
 
1231
        tree.add('a file', b'a-file-id')
1222
1232
        # Note: dirstate does not sha prior to the first commit
1223
1233
        # so commit now in order for the test to work
1224
1234
        tree.commit('first')
1229
1239
        state = dirstate.DirState.from_tree(tree, 'dirstate',
1230
1240
            UppercaseSHA1Provider())
1231
1241
        self.addCleanup(state.unlock)
1232
 
        expected_sha = osutils.sha_string(text.upper() + "foo")
1233
 
        entry = state._get_entry(0, path_utf8='a file')
 
1242
        expected_sha = osutils.sha_string(text.upper() + b"foo")
 
1243
        entry = state._get_entry(0, path_utf8=b'a file')
 
1244
        self.assertNotEqual((None, None), entry)
1234
1245
        state._sha_cutoff_time()
1235
1246
        state._cutoff_time += 10
1236
1247
        sha1 = self.update_entry(state, entry, 'tree/a file',
1247
1258
        # changed
1248
1259
        file_ids_changed = [change[0] for change
1249
1260
                            in tree.iter_changes(tree.basis_tree())]
1250
 
        self.assertEqual(['a-file-id'], file_ids_changed)
 
1261
        self.assertEqual([b'a-file-id'], file_ids_changed)
1251
1262
 
1252
1263
 
1253
1264
class UppercaseSHA1Provider(dirstate.SHA1Provider):
1257
1268
        return self.stat_and_sha1(abspath)[1]
1258
1269
 
1259
1270
    def stat_and_sha1(self, abspath):
1260
 
        file_obj = file(abspath, 'rb')
1261
 
        try:
 
1271
        with open(abspath, 'rb') as file_obj:
1262
1272
            statvalue = os.fstat(file_obj.fileno())
1263
 
            text = ''.join(file_obj.readlines())
1264
 
            sha1 = osutils.sha_string(text.upper() + "foo")
1265
 
        finally:
1266
 
            file_obj.close()
 
1273
            text = b''.join(file_obj.readlines())
 
1274
            sha1 = osutils.sha_string(text.upper() + b"foo")
1267
1275
        return statvalue, sha1
1268
1276
 
1269
1277
 
1270
1278
class TestProcessEntry(test_dirstate.TestCaseWithDirState):
1271
1279
 
 
1280
    scenarios = multiply_scenarios(dir_reader_scenarios(), pe_scenarios)
 
1281
 
1272
1282
    # Set by load_tests
1273
1283
    _process_entry = None
1274
1284
 
1299
1309
        basis_tree = tree.basis_tree()
1300
1310
        def is_inside_raises(*args, **kwargs):
1301
1311
            raise RuntimeError('stop this')
1302
 
        self.overrideAttr(osutils, 'is_inside', is_inside_raises)
 
1312
        self.overrideAttr(dirstate, 'is_inside', is_inside_raises)
 
1313
        try:
 
1314
            from breezy.bzr import _dirstate_helpers_pyx
 
1315
        except ImportError:
 
1316
            pass
 
1317
        else:
 
1318
            self.overrideAttr(_dirstate_helpers_pyx, 'is_inside', is_inside_raises)
1303
1319
        self.assertListRaises(RuntimeError, tree.iter_changes, basis_tree)
1304
1320
 
1305
1321
    def test_simple_changes(self):
1306
1322
        tree = self.make_branch_and_tree('tree')
1307
1323
        self.build_tree(['tree/file'])
1308
 
        tree.add(['file'], ['file-id'])
1309
 
        self.assertChangedFileIds([tree.get_root_id(), 'file-id'], tree)
 
1324
        tree.add(['file'], [b'file-id'])
 
1325
        self.assertChangedFileIds([tree.get_root_id(), b'file-id'], tree)
1310
1326
        tree.commit('one')
1311
1327
        self.assertChangedFileIds([], tree)
1312
1328
 
1313
1329
    def test_sha1provider_stat_and_sha1_used(self):
1314
1330
        tree = self.make_branch_and_tree('tree')
1315
1331
        self.build_tree(['tree/file'])
1316
 
        tree.add(['file'], ['file-id'])
 
1332
        tree.add(['file'], [b'file-id'])
1317
1333
        tree.commit('one')
1318
1334
        tree.lock_write()
1319
1335
        self.addCleanup(tree.unlock)
1320
1336
        state = tree._current_dirstate()
1321
1337
        state._sha1_provider = UppercaseSHA1Provider()
1322
 
        self.assertChangedFileIds(['file-id'], tree)
1323
 
 
 
1338
        self.assertChangedFileIds([b'file-id'], tree)
 
1339
 
 
1340
 
 
1341
class TestPackStat(tests.TestCase):
 
1342
    """Check packed representaton of stat values is robust on all inputs"""
 
1343
 
 
1344
    scenarios = helper_scenarios
 
1345
 
 
1346
    def pack(self, statlike_tuple):
 
1347
        return self.helpers.pack_stat(os.stat_result(statlike_tuple))
 
1348
 
 
1349
    @staticmethod
 
1350
    def unpack_field(packed_string, stat_field):
 
1351
        return _dirstate_helpers_py._unpack_stat(packed_string)[stat_field]
 
1352
 
 
1353
    def test_result(self):
 
1354
        self.assertEqual(b"AAAQAAAAABAAAAARAAAAAgAAAAEAAIHk",
 
1355
            self.pack((33252, 1, 2, 0, 0, 0, 4096, 15.5, 16.5, 17.5)))
 
1356
 
 
1357
    def test_giant_inode(self):
 
1358
        packed = self.pack((33252, 0xF80000ABC, 0, 0, 0, 0, 0, 0, 0, 0))
 
1359
        self.assertEqual(0x80000ABC, self.unpack_field(packed, "st_ino"))
 
1360
 
 
1361
    def test_giant_size(self):
 
1362
        packed = self.pack((33252, 0, 0, 0, 0, 0, (1 << 33) + 4096, 0, 0, 0))
 
1363
        self.assertEqual(4096, self.unpack_field(packed, "st_size"))
 
1364
 
 
1365
    def test_fractional_mtime(self):
 
1366
        packed = self.pack((33252, 0, 0, 0, 0, 0, 0, 0, 16.9375, 0))
 
1367
        self.assertEqual(16, self.unpack_field(packed, "st_mtime"))
 
1368
 
 
1369
    def test_ancient_mtime(self):
 
1370
        packed = self.pack((33252, 0, 0, 0, 0, 0, 0, 0, -11644473600.0, 0))
 
1371
        self.assertEqual(1240428288, self.unpack_field(packed, "st_mtime"))
 
1372
 
 
1373
    def test_distant_mtime(self):
 
1374
        packed = self.pack((33252, 0, 0, 0, 0, 0, 0, 0, 64060588800.0, 0))
 
1375
        self.assertEqual(3931046656, self.unpack_field(packed, "st_mtime"))
 
1376
 
 
1377
    def test_fractional_ctime(self):
 
1378
        packed = self.pack((33252, 0, 0, 0, 0, 0, 0, 0, 0, 17.5625))
 
1379
        self.assertEqual(17, self.unpack_field(packed, "st_ctime"))
 
1380
 
 
1381
    def test_ancient_ctime(self):
 
1382
        packed = self.pack((33252, 0, 0, 0, 0, 0, 0, 0, 0, -11644473600.0))
 
1383
        self.assertEqual(1240428288, self.unpack_field(packed, "st_ctime"))
 
1384
 
 
1385
    def test_distant_ctime(self):
 
1386
        packed = self.pack((33252, 0, 0, 0, 0, 0, 0, 0, 0, 64060588800.0))
 
1387
        self.assertEqual(3931046656, self.unpack_field(packed, "st_ctime"))
 
1388
 
 
1389
    def test_negative_dev(self):
 
1390
        packed = self.pack((33252, 0, -0xFFFFFCDE, 0, 0, 0, 0, 0, 0, 0))
 
1391
        self.assertEqual(0x322, self.unpack_field(packed, "st_dev"))