~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/per_workingtree/test_workingtree.py

  • Committer: Tarmac
  • Author(s): Vincent Ladeuil
  • Date: 2017-01-30 14:42:05 UTC
  • mfrom: (6620.1.1 trunk)
  • Revision ID: tarmac-20170130144205-r8fh2xpmiuxyozpv
Merge  2.7 into trunk including fix for bug #1657238 [r=vila]

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2006-2011 Canonical Ltd
 
1
# Copyright (C) 2006-2012, 2016 Canonical Ltd
2
2
# Authors:  Robert Collins <robert.collins@canonical.com>
3
3
#           and others
4
4
#
22
22
 
23
23
from bzrlib import (
24
24
    branch,
25
 
    branchbuilder,
26
25
    bzrdir,
 
26
    config,
 
27
    controldir,
27
28
    errors,
28
29
    osutils,
 
30
    revision as _mod_revision,
29
31
    symbol_versioning,
30
32
    tests,
 
33
    trace,
31
34
    urlutils,
32
35
    )
33
36
from bzrlib.errors import (
35
38
    PathsNotVersionedError,
36
39
    )
37
40
from bzrlib.inventory import Inventory
 
41
from bzrlib.mutabletree import MutableTree
38
42
from bzrlib.osutils import pathjoin, getcwd, has_symlinks
39
 
from bzrlib.tests import TestSkipped, TestNotApplicable
 
43
from bzrlib.tests import (
 
44
    features,
 
45
    TestSkipped,
 
46
    TestNotApplicable,
 
47
    )
40
48
from bzrlib.tests.per_workingtree import TestCaseWithWorkingTree
41
49
from bzrlib.workingtree import (
42
50
    TreeDirectory,
50
58
 
51
59
class TestWorkingTree(TestCaseWithWorkingTree):
52
60
 
 
61
    def requireBranchReference(self):
 
62
        test_branch = self.make_branch('test-branch')
 
63
        try:
 
64
            # if there is a working tree now, this is not supported.
 
65
            test_branch.bzrdir.open_workingtree()
 
66
            raise TestNotApplicable("only on trees that can be separate"
 
67
                " from their branch.")
 
68
        except (errors.NoWorkingTree, errors.NotLocalUrl):
 
69
            pass
 
70
 
53
71
    def test_branch_builder(self):
54
72
        # Just a smoke test that we get a branch at the specified relpath
55
73
        builder = self.make_branch_builder('foobar')
56
 
        br = branch.Branch.open('foobar')
 
74
        br = branch.Branch.open(self.get_url('foobar'))
57
75
 
58
76
    def test_list_files(self):
59
77
        tree = self.make_branch_and_tree('.')
114
132
        self.assertEqual(('filename', 'V', 'directory', 'file-id'),
115
133
                         result[0][:4])
116
134
 
 
135
    def test_get_config_stack(self):
 
136
        # Smoke test that all working trees succeed getting a config
 
137
        wt = self.make_branch_and_tree('.')
 
138
        conf = wt.get_config_stack()
 
139
        self.assertIsInstance(conf, config.Stack)
 
140
 
117
141
    def test_open_containing(self):
118
 
        branch = self.make_branch_and_tree('.').branch
119
 
        local_base = urlutils.local_path_from_url(branch.base)
 
142
        local_wt = self.make_branch_and_tree('.')
 
143
        local_url = local_wt.bzrdir.root_transport.base
 
144
        local_base = urlutils.local_path_from_url(local_url)
 
145
        del local_wt
120
146
 
121
147
        # Empty opens '.'
122
148
        wt, relpath = WorkingTree.open_containing()
154
180
 
155
181
    def test_lock_locks_branch(self):
156
182
        tree = self.make_branch_and_tree('.')
 
183
        self.assertEqual(None, tree.branch.peek_lock_mode())
157
184
        tree.lock_read()
158
185
        self.assertEqual('r', tree.branch.peek_lock_mode())
159
186
        tree.unlock()
168
195
        tree = self.make_branch_and_tree('.')
169
196
 
170
197
        self.build_tree(['hello.txt'])
171
 
        file('hello.txt', 'w').write('initial hello')
 
198
        with file('hello.txt', 'w') as f: f.write('initial hello')
172
199
 
173
200
        self.assertRaises(PathsNotVersionedError,
174
201
                          tree.revert, ['hello.txt'])
176
203
        tree.commit('create initial hello.txt')
177
204
 
178
205
        self.check_file_contents('hello.txt', 'initial hello')
179
 
        file('hello.txt', 'w').write('new hello')
 
206
        with file('hello.txt', 'w') as f: f.write('new hello')
180
207
        self.check_file_contents('hello.txt', 'new hello')
181
208
 
182
209
        # revert file modified since last revision
190
217
        self.check_file_contents('hello.txt.~1~', 'new hello')
191
218
 
192
219
        # backup files are numbered
193
 
        file('hello.txt', 'w').write('new hello2')
 
220
        with file('hello.txt', 'w') as f: f.write('new hello2')
194
221
        tree.revert(['hello.txt'])
195
222
        self.check_file_contents('hello.txt', 'initial hello')
196
223
        self.check_file_contents('hello.txt.~1~', 'new hello')
199
226
    def test_revert_missing(self):
200
227
        # Revert a file that has been deleted since last commit
201
228
        tree = self.make_branch_and_tree('.')
202
 
        file('hello.txt', 'w').write('initial hello')
 
229
        with file('hello.txt', 'w') as f: f.write('initial hello')
203
230
        tree.add('hello.txt')
204
231
        tree.commit('added hello.txt')
205
232
        os.unlink('hello.txt')
211
238
        tree = self.make_branch_and_tree('.')
212
239
        self.build_tree(['hello.txt'])
213
240
        tree.add('hello.txt')
214
 
        self.assertEquals(list(tree.unknowns()),
 
241
        self.assertEqual(list(tree.unknowns()),
215
242
                          [])
216
243
 
217
244
    def test_unknowns(self):
220
247
                         'hello.txt.~1~'])
221
248
        self.build_tree_contents([('.bzrignore', '*.~*\n')])
222
249
        tree.add('.bzrignore')
223
 
        self.assertEquals(list(tree.unknowns()),
 
250
        self.assertEqual(list(tree.unknowns()),
224
251
                          ['hello.txt'])
225
252
 
226
253
    def test_initialize(self):
243
270
 
244
271
        wt.commit('create initial state')
245
272
 
246
 
        revid = b.revision_history()[0]
 
273
        revid = b.last_revision()
247
274
        self.log('first revision_id is {%s}' % revid)
248
275
 
249
276
        tree = b.repository.revision_tree(revid)
272
299
        wt = self.make_branch_and_tree('.')
273
300
        self.build_tree(['foo/',
274
301
                         'foo/hello'])
275
 
        self.assertRaises(NotVersionedError,
276
 
                          wt.add,
277
 
                          'foo/hello')
 
302
        if not wt._format.supports_versioned_directories:
 
303
            wt.add('foo/hello')
 
304
        else:
 
305
            self.assertRaises(NotVersionedError,
 
306
                              wt.add,
 
307
                              'foo/hello')
278
308
 
279
309
    def test_add_missing(self):
280
310
        # adding a msising file -> NoSuchFile
303
333
        cloned = cloned_dir.open_workingtree()
304
334
        self.assertEqual(cloned.get_parent_ids(), wt.get_parent_ids())
305
335
 
 
336
    def test_clone_empty(self):
 
337
        wt = self.make_branch_and_tree('source')
 
338
        cloned_dir = wt.bzrdir.clone('target', revision_id=_mod_revision.NULL_REVISION)
 
339
        cloned = cloned_dir.open_workingtree()
 
340
        self.assertEqual(cloned.get_parent_ids(), wt.get_parent_ids())
 
341
 
306
342
    def test_last_revision(self):
307
343
        wt = self.make_branch_and_tree('source')
308
344
        self.assertEqual([], wt.get_parent_ids())
320
356
        wt.set_last_revision('null:')
321
357
        wt.commit('A', allow_pointless=True, rev_id='A')
322
358
        self.assertEqual(['A'], wt.get_parent_ids())
323
 
        # None is aways in the branch
 
359
        # null: is aways in the branch
324
360
        wt.set_last_revision('null:')
325
361
        self.assertEqual([], wt.get_parent_ids())
326
362
        # and now we can set it to 'A'
327
363
        # because some formats mutate the branch to set it on the tree
328
364
        # we need to alter the branch to let this pass.
329
 
        try:
330
 
            self.applyDeprecated(symbol_versioning.deprecated_in((2, 4, 0)),
331
 
                wt.branch.set_revision_history, ['A', 'B'])
332
 
        except errors.NoSuchRevision, e:
333
 
            self.assertEqual('B', e.revision)
 
365
        if getattr(wt.branch, "_set_revision_history", None) is None:
334
366
            raise TestSkipped("Branch format does not permit arbitrary"
335
367
                              " history")
 
368
        wt.branch._set_revision_history(['A', 'B'])
336
369
        wt.set_last_revision('A')
337
370
        self.assertEqual(['A'], wt.get_parent_ids())
338
371
        self.assertRaises(errors.ReservedId, wt.set_last_revision, 'A:')
346
379
        # that formats where initialising a branch does not initialise a
347
380
        # tree - and thus have separable entities - support skewing the
348
381
        # two things.
349
 
        branch = self.make_branch('tree')
350
 
        try:
351
 
            # if there is a working tree now, this is not supported.
352
 
            branch.bzrdir.open_workingtree()
353
 
            return
354
 
        except errors.NoWorkingTree:
355
 
            pass
356
 
        wt = branch.bzrdir.create_workingtree()
 
382
        self.requireBranchReference()
 
383
        wt = self.make_branch_and_tree('tree')
357
384
        wt.commit('A', allow_pointless=True, rev_id='A')
358
385
        wt.set_last_revision(None)
359
386
        self.assertEqual([], wt.get_parent_ids())
436
463
            revision_id='a')
437
464
        self.assertEqual(['a'], made_tree.get_parent_ids())
438
465
 
 
466
    def test_post_build_tree_hook(self):
 
467
        calls = []
 
468
        def track_post_build_tree(tree):
 
469
            calls.append(tree.last_revision())
 
470
        source = self.make_branch_and_tree('source')
 
471
        source.commit('a', rev_id='a', allow_pointless=True)
 
472
        source.commit('b', rev_id='b', allow_pointless=True)
 
473
        self.build_tree(['new/'])
 
474
        made_control = self.bzrdir_format.initialize('new')
 
475
        source.branch.repository.clone(made_control)
 
476
        source.branch.clone(made_control)
 
477
        MutableTree.hooks.install_named_hook("post_build_tree",
 
478
            track_post_build_tree, "Test")
 
479
        made_tree = self.workingtree_format.initialize(made_control,
 
480
            revision_id='a')
 
481
        self.assertEqual(['a'], calls)
 
482
 
439
483
    def test_update_sets_last_revision(self):
440
484
        # working tree formats from the meta-dir format and newer support
441
485
        # setting the last revision on a tree independently of that on the
445
489
        # that formats where initialising a branch does not initialise a
446
490
        # tree - and thus have separable entities - support skewing the
447
491
        # two things.
448
 
        main_branch = self.make_branch('tree')
449
 
        try:
450
 
            # if there is a working tree now, this is not supported.
451
 
            main_branch.bzrdir.open_workingtree()
452
 
            return
453
 
        except errors.NoWorkingTree:
454
 
            pass
455
 
        wt = main_branch.bzrdir.create_workingtree()
 
492
        self.requireBranchReference()
 
493
        wt = self.make_branch_and_tree('tree')
456
494
        # create an out of date working tree by making a checkout in this
457
495
        # current format
458
496
        self.build_tree(['checkout/', 'tree/file'])
459
497
        checkout = bzrdir.BzrDirMetaFormat1().initialize('checkout')
460
 
        branch.BranchReferenceFormat().initialize(checkout,
461
 
            target_branch=main_branch)
 
498
        checkout.set_branch_reference(wt.branch)
462
499
        old_tree = self.workingtree_format.initialize(checkout)
463
500
        # now commit to 'tree'
464
501
        wt.add('file')
513
550
        # that formats where initialising a branch does not initialise a
514
551
        # tree - and thus have separable entities - support skewing the
515
552
        # two things.
516
 
        main_branch = self.make_branch('tree')
517
 
        try:
518
 
            # if there is a working tree now, this is not supported.
519
 
            main_branch.bzrdir.open_workingtree()
520
 
            return
521
 
        except errors.NoWorkingTree:
522
 
            pass
523
 
        wt = main_branch.bzrdir.create_workingtree()
 
553
        self.requireBranchReference()
 
554
        wt = self.make_branch_and_tree('tree')
524
555
        # create an out of date working tree by making a checkout in this
525
556
        # current format
526
557
        self.build_tree(['checkout/', 'tree/file'])
527
558
        checkout = bzrdir.BzrDirMetaFormat1().initialize('checkout')
528
 
        branch.BranchReferenceFormat().initialize(checkout,
529
 
            target_branch=main_branch)
 
559
        checkout.set_branch_reference(wt.branch)
530
560
        old_tree = self.workingtree_format.initialize(checkout)
531
561
        # now commit to 'tree'
532
562
        wt.add('file')
614
644
        # which should have pivoted the local tip into a merge
615
645
        self.assertEqual([master_tip, 'bar'], tree.get_parent_ids())
616
646
        # and the local branch history should match the masters now.
617
 
        self.assertEqual(master_tree.branch.revision_history(),
618
 
            tree.branch.revision_history())
 
647
        self.assertEqual(master_tree.branch.last_revision(),
 
648
            tree.branch.last_revision())
619
649
 
620
650
    def test_update_takes_revision_parameter(self):
621
651
        wt = self.make_branch_and_tree('wt')
635
665
        # FIXME: This doesn't really test that it works; also this is not
636
666
        # implementation-independent. mbp 20070226
637
667
        tree = self.make_branch_and_tree('master')
 
668
        if not isinstance(tree, InventoryWorkingTree):
 
669
            raise TestNotApplicable("merge-hashes is specific to bzr "
 
670
                "working trees")
638
671
        tree._transport.put_bytes('merge-hashes', 'asdfasdf')
639
672
        self.assertRaises(errors.MergeModifiedFormatError, tree.merge_modified)
640
673
 
648
681
            tree.add(['somefile'], ['file-id'])
649
682
            tree.set_merge_modified(d)
650
683
            mm = tree.merge_modified()
651
 
            self.assertEquals(mm, d)
 
684
            self.assertEqual(mm, d)
652
685
        finally:
653
686
            tree.unlock()
654
687
        mm = tree.merge_modified()
655
 
        self.assertEquals(mm, d)
 
688
        self.assertEqual(mm, d)
656
689
 
657
690
    def test_conflicts(self):
658
691
        from bzrlib.tests.test_conflicts import example_conflicts
674
707
    def make_merge_conflicts(self):
675
708
        from bzrlib.merge import merge_inner
676
709
        tree = self.make_branch_and_tree('mine')
677
 
        file('mine/bloo', 'wb').write('one')
678
 
        file('mine/blo', 'wb').write('on')
 
710
        with file('mine/bloo', 'wb') as f: f.write('one')
 
711
        with file('mine/blo', 'wb') as f: f.write('on')
679
712
        tree.add(['bloo', 'blo'])
680
713
        tree.commit("blah", allow_pointless=False)
681
714
        base = tree.branch.repository.revision_tree(tree.last_revision())
682
 
        bzrdir.BzrDir.open("mine").sprout("other")
683
 
        file('other/bloo', 'wb').write('two')
 
715
        controldir.ControlDir.open("mine").sprout("other")
 
716
        with file('other/bloo', 'wb') as f: f.write('two')
684
717
        othertree = WorkingTree.open('other')
685
718
        othertree.commit('blah', allow_pointless=False)
686
 
        file('mine/bloo', 'wb').write('three')
 
719
        with file('mine/bloo', 'wb') as f: f.write('three')
687
720
        tree.commit("blah", allow_pointless=False)
688
721
        merge_inner(tree.branch, othertree, base, this_tree=tree)
689
722
        return tree
928
961
            case_sensitive = True
929
962
        tree = self.make_branch_and_tree('test')
930
963
        self.assertEqual(case_sensitive, tree.case_sensitive)
 
964
        if not isinstance(tree, InventoryWorkingTree):
 
965
            raise TestNotApplicable("get_format_string is only available "
 
966
                                    "on bzr working trees")
931
967
        # now we cheat, and make a file that matches the case-sensitive name
932
968
        t = tree.bzrdir.get_workingtree_transport(None)
933
969
        try:
939
975
        tree = tree.bzrdir.open_workingtree()
940
976
        self.assertFalse(tree.case_sensitive)
941
977
 
 
978
    def test_supports_executable(self):
 
979
        self.build_tree(['filename'])
 
980
        tree = self.make_branch_and_tree('.')
 
981
        tree.add('filename')
 
982
        self.assertIsInstance(tree._supports_executable(), bool)
 
983
        if tree._supports_executable():
 
984
            tree.lock_read()
 
985
            try:
 
986
                self.assertFalse(tree.is_executable(tree.path2id('filename')))
 
987
            finally:
 
988
                tree.unlock()
 
989
            os.chmod('filename', 0755)
 
990
            self.addCleanup(tree.lock_read().unlock)
 
991
            self.assertTrue(tree.is_executable(tree.path2id('filename')))
 
992
        else:
 
993
            self.addCleanup(tree.lock_read().unlock)
 
994
            self.assertFalse(tree.is_executable(tree.path2id('filename')))
 
995
 
942
996
    def test_all_file_ids_with_missing(self):
943
997
        tree = self.make_branch_and_tree('tree')
944
998
        tree.lock_write()
989
1043
            4 5-M
990
1044
            |
991
1045
            W
992
 
         """
993
 
        builder = branchbuilder.BranchBuilder(
994
 
            self.get_transport(),
995
 
            format=self.workingtree_format._matchingbzrdir)
 
1046
        """
 
1047
        format = self.workingtree_format.get_controldir_for_branch()
 
1048
        builder = self.make_branch_builder(".", format=format)
996
1049
        builder.start_series()
997
1050
        # mainline
998
1051
        builder.build_snapshot(
1085
1138
        if osutils.normalizes_filenames():
1086
1139
            # You *can't* create an illegal filename on OSX.
1087
1140
            raise tests.TestNotApplicable('OSX normalizes filenames')
1088
 
        self.requireFeature(tests.UTF8Filesystem)
 
1141
        self.requireFeature(features.UTF8Filesystem)
1089
1142
        # We require a UTF8 filesystem, because otherwise we would need to get
1090
1143
        # tricky to figure out how to create an illegal filename.
1091
1144
        # \xb5 is an illegal path because it should be \xc2\xb5 for UTF-8
1115
1168
 
1116
1169
class TestControlComponent(TestCaseWithWorkingTree):
1117
1170
    """WorkingTree implementations adequately implement ControlComponent."""
1118
 
    
 
1171
 
1119
1172
    def test_urls(self):
1120
1173
        wt = self.make_branch_and_tree('wt')
1121
1174
        self.assertIsInstance(wt.user_url, str)
1146
1199
 
1147
1200
    def test_set_in_branch(self):
1148
1201
        wt = self.make_wt_with_worth_saving_limit()
1149
 
        config = wt.branch.get_config()
1150
 
        config.set_user_option('bzr.workingtree.worth_saving_limit', '20')
 
1202
        conf = wt.get_config_stack()
 
1203
        conf.set('bzr.workingtree.worth_saving_limit', '20')
1151
1204
        self.assertEqual(20, wt._worth_saving_limit())
1152
1205
        ds = wt.current_dirstate()
1153
1206
        self.assertEqual(10, ds._worth_saving_limit)
1154
1207
 
1155
1208
    def test_invalid(self):
1156
1209
        wt = self.make_wt_with_worth_saving_limit()
1157
 
        config = wt.branch.get_config()
1158
 
        config.set_user_option('bzr.workingtree.worth_saving_limit', 'a')
 
1210
        conf = wt.get_config_stack()
 
1211
        conf.set('bzr.workingtree.worth_saving_limit', 'a')
1159
1212
        # If the config entry is invalid, default to 10
1160
 
        # TODO: This writes a warning to the user, trap it somehow
 
1213
        warnings = []
 
1214
        def warning(*args):
 
1215
            warnings.append(args[0] % args[1:])
 
1216
        self.overrideAttr(trace, 'warning', warning)
1161
1217
        self.assertEqual(10, wt._worth_saving_limit())
 
1218
        self.assertLength(1, warnings)
 
1219
        self.assertEqual('Value "a" is not valid for'
 
1220
                          ' "bzr.workingtree.worth_saving_limit"',
 
1221
                          warnings[0])
1162
1222
 
1163
1223
 
1164
1224
class TestFormatAttributes(TestCaseWithWorkingTree):