/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-04-02 00:52:27 UTC
  • mfrom: (6939 work)
  • mto: This revision was merged to the branch mainline in revision 7274.
  • Revision ID: jelmer@jelmer.uk-20180402005227-pecflp1mvdjrjqd6
Merge trunk.

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):
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):
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."""
492
476
        self.assertCmpByDirs(-1, 'ab/cd', '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', 'str')
 
481
        self.assertRaises(TypeError, lt_by_dirs, '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
485
        self.assertCmpByDirs(-1, '\xc2\xb5', '\xc3\xa5') # u'\xb5', u'\xe5'
505
489
        self.assertCmpByDirs(-1, 'b/a', 'b/\xc2\xb5') # u'b/a', u'b/\xb5'
506
490
 
507
491
 
508
 
class TestCompiledCmpByDirs(TestCmpByDirs):
509
 
    """Test the pyrex implementation of cmp_by_dirs"""
 
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
544
528
            return dirname.split('/'), 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(['', 'a', 'ab', 'abc', 'a/b/c', 'b/d/e'])
 
543
        self.assertLtPathByDirblock(['kl', 'ab/cd', 'ab/ef', 'gh/ij'])
571
544
 
572
545
    def test_tricky_paths(self):
573
 
        self.assertCmpPathByDirblock([
 
546
        self.assertLtPathByDirblock([
574
547
            # Contents of ''
575
548
            '', 'a', 'a-a', 'a=a', 'b',
576
549
            # Contents of 'a'
598
571
            # Contents of 'b',
599
572
            'b/a', 'b/b',
600
573
            ])
601
 
        self.assertCmpPathByDirblock([
 
574
        self.assertLtPathByDirblock([
602
575
                 # content of '/'
603
576
                 '', 'a', 'a-a', 'a-z', 'a=a', 'a=z',
604
577
                 # content of 'a/'
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
616
            '', 'a', '\xc2\xb5', '\xc3\xa5',
644
617
            # content of 'a'
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()
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, '')
 
818
        state.add('a', b'a-id', 'file', None, '')
841
819
        entry = state._get_entry(0, path_utf8='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)
 
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)
851
831
        state._observed_sha1(entry, "foo", statvalue)
852
832
        self.assertEqual('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(
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)
 
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
896
885
        self.assertEqual(('f', '', 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
 
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
907
        self.assertEqual(('f', '', 14, False, dirstate.DirState.NULLSTAT),
920
908
                         entry[1][0])
930
918
        self.assertEqual([('is_exec', mode, False)], state._log)
931
919
        self.assertEqual(('f', '', 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.
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,
977
967
        # Dirblock is not updated (the link is too new)
978
968
        self.assertEqual([('l', '', 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
 
976
        del state._log[:]
984
977
        link_or_sha1 = self.update_entry(state, entry, abspath='a',
985
978
                                          stat_value=stat_value)
986
979
        self.assertEqual('target', link_or_sha1)
987
 
        self.assertEqual([('read_link', 'a', ''),
988
 
                          ('read_link', 'a', ''),
989
 
                         ], state._log)
 
980
        self.assertEqual([('read_link', 'a', '')], state._log)
990
981
        self.assertEqual([('l', '', 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
 
985
        del state._log[:]
993
986
        link_or_sha1 = self.update_entry(state, entry, abspath='a',
994
987
                                          stat_value=stat_value)
 
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)
995
993
        self.assertEqual('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)
 
995
        self.assertEqual([('read_link', 'a', '')], state._log)
1001
996
        self.assertEqual([('l', '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)
 
1001
        self.assertEqual([], state._log)
1009
1002
        link_or_sha1 = self.update_entry(state, entry, abspath='a',
1010
1003
                                          stat_value=stat_value)
1011
1004
        self.assertEqual('target', link_or_sha1)
1026
1019
        self.build_tree(['a/'])
1027
1020
        state.adjust_time(+20)
1028
1021
        self.assertIs(None, self.do_update_entry(state, entry, '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, '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, '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(
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, '')
1067
1077
        self.build_tree(['r/'])
1068
1078
        entry = state._get_entry(0, path_utf8='r')
1069
1079
        self.do_update_entry(state, entry, 'r')
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)
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')
1269
1279
 
1270
1280
class TestProcessEntry(test_dirstate.TestCaseWithDirState):
1271
1281
 
 
1282
    scenarios = multiply_scenarios(dir_reader_scenarios(), pe_scenarios)
 
1283
 
1272
1284
    # Set by load_tests
1273
1285
    _process_entry = None
1274
1286
 
1305
1317
    def test_simple_changes(self):
1306
1318
        tree = self.make_branch_and_tree('tree')
1307
1319
        self.build_tree(['tree/file'])
1308
 
        tree.add(['file'], ['file-id'])
1309
 
        self.assertChangedFileIds([tree.get_root_id(), 'file-id'], tree)
 
1320
        tree.add(['file'], [b'file-id'])
 
1321
        self.assertChangedFileIds([tree.get_root_id(), b'file-id'], tree)
1310
1322
        tree.commit('one')
1311
1323
        self.assertChangedFileIds([], tree)
1312
1324
 
1313
1325
    def test_sha1provider_stat_and_sha1_used(self):
1314
1326
        tree = self.make_branch_and_tree('tree')
1315
1327
        self.build_tree(['tree/file'])
1316
 
        tree.add(['file'], ['file-id'])
 
1328
        tree.add(['file'], [b'file-id'])
1317
1329
        tree.commit('one')
1318
1330
        tree.lock_write()
1319
1331
        self.addCleanup(tree.unlock)
1320
1332
        state = tree._current_dirstate()
1321
1333
        state._sha1_provider = UppercaseSHA1Provider()
1322
 
        self.assertChangedFileIds(['file-id'], tree)
1323
 
 
 
1334
        self.assertChangedFileIds([b'file-id'], tree)
 
1335
 
 
1336
 
 
1337
class TestPackStat(tests.TestCase):
 
1338
    """Check packed representaton of stat values is robust on all inputs"""
 
1339
 
 
1340
    scenarios = helper_scenarios
 
1341
 
 
1342
    def pack(self, statlike_tuple):
 
1343
        return self.helpers.pack_stat(os.stat_result(statlike_tuple))
 
1344
 
 
1345
    @staticmethod
 
1346
    def unpack_field(packed_string, stat_field):
 
1347
        return _dirstate_helpers_py._unpack_stat(packed_string)[stat_field]
 
1348
 
 
1349
    def test_result(self):
 
1350
        self.assertEqual("AAAQAAAAABAAAAARAAAAAgAAAAEAAIHk",
 
1351
            self.pack((33252, 1, 2, 0, 0, 0, 4096, 15.5, 16.5, 17.5)))
 
1352
 
 
1353
    def test_giant_inode(self):
 
1354
        packed = self.pack((33252, 0xF80000ABC, 0, 0, 0, 0, 0, 0, 0, 0))
 
1355
        self.assertEqual(0x80000ABC, self.unpack_field(packed, "st_ino"))
 
1356
 
 
1357
    def test_giant_size(self):
 
1358
        packed = self.pack((33252, 0, 0, 0, 0, 0, (1 << 33) + 4096, 0, 0, 0))
 
1359
        self.assertEqual(4096, self.unpack_field(packed, "st_size"))
 
1360
 
 
1361
    def test_fractional_mtime(self):
 
1362
        packed = self.pack((33252, 0, 0, 0, 0, 0, 0, 0, 16.9375, 0))
 
1363
        self.assertEqual(16, self.unpack_field(packed, "st_mtime"))
 
1364
 
 
1365
    def test_ancient_mtime(self):
 
1366
        packed = self.pack((33252, 0, 0, 0, 0, 0, 0, 0, -11644473600.0, 0))
 
1367
        self.assertEqual(1240428288, self.unpack_field(packed, "st_mtime"))
 
1368
 
 
1369
    def test_distant_mtime(self):
 
1370
        packed = self.pack((33252, 0, 0, 0, 0, 0, 0, 0, 64060588800.0, 0))
 
1371
        self.assertEqual(3931046656, self.unpack_field(packed, "st_mtime"))
 
1372
 
 
1373
    def test_fractional_ctime(self):
 
1374
        packed = self.pack((33252, 0, 0, 0, 0, 0, 0, 0, 0, 17.5625))
 
1375
        self.assertEqual(17, self.unpack_field(packed, "st_ctime"))
 
1376
 
 
1377
    def test_ancient_ctime(self):
 
1378
        packed = self.pack((33252, 0, 0, 0, 0, 0, 0, 0, 0, -11644473600.0))
 
1379
        self.assertEqual(1240428288, self.unpack_field(packed, "st_ctime"))
 
1380
 
 
1381
    def test_distant_ctime(self):
 
1382
        packed = self.pack((33252, 0, 0, 0, 0, 0, 0, 0, 0, 64060588800.0))
 
1383
        self.assertEqual(3931046656, self.unpack_field(packed, "st_ctime"))
 
1384
 
 
1385
    def test_negative_dev(self):
 
1386
        packed = self.pack((33252, 0, -0xFFFFFCDE, 0, 0, 0, 0, 0, 0, 0))
 
1387
        self.assertEqual(0x322, self.unpack_field(packed, "st_dev"))