~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

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

Merge bzr.dev, update to use new hooks.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2006-2010 Canonical Ltd
 
1
# Copyright (C) 2006-2011 Canonical Ltd
2
2
# Authors:  Robert Collins <robert.collins@canonical.com>
3
3
#           and others
4
4
#
19
19
from cStringIO import StringIO
20
20
import errno
21
21
import os
22
 
import sys
23
22
 
24
23
from bzrlib import (
25
24
    branch,
26
 
    branchbuilder,
27
25
    bzrdir,
 
26
    config,
28
27
    errors,
29
28
    osutils,
 
29
    revision as _mod_revision,
 
30
    symbol_versioning,
30
31
    tests,
 
32
    trace,
31
33
    urlutils,
32
 
    workingtree,
33
 
    )
34
 
from bzrlib.errors import (NotBranchError, NotVersionedError,
35
 
                           UnsupportedOperation, PathsNotVersionedError)
 
34
    )
 
35
from bzrlib.errors import (
 
36
    UnsupportedOperation,
 
37
    PathsNotVersionedError,
 
38
    )
36
39
from bzrlib.inventory import Inventory
37
40
from bzrlib.osutils import pathjoin, getcwd, has_symlinks
38
 
from bzrlib.tests import TestSkipped, TestNotApplicable
 
41
from bzrlib.tests import (
 
42
    features,
 
43
    TestSkipped,
 
44
    TestNotApplicable,
 
45
    )
39
46
from bzrlib.tests.per_workingtree import TestCaseWithWorkingTree
40
 
from bzrlib.trace import mutter
41
 
from bzrlib.workingtree import (TreeEntry, TreeDirectory, TreeFile, TreeLink,
42
 
                                WorkingTree, WorkingTree2)
 
47
from bzrlib.workingtree import (
 
48
    TreeDirectory,
 
49
    TreeFile,
 
50
    TreeLink,
 
51
    InventoryWorkingTree,
 
52
    WorkingTree,
 
53
    )
43
54
from bzrlib.conflicts import ConflictList, TextConflict, ContentsConflict
44
55
 
45
56
 
46
57
class TestWorkingTree(TestCaseWithWorkingTree):
47
58
 
 
59
    def test_branch_builder(self):
 
60
        # Just a smoke test that we get a branch at the specified relpath
 
61
        builder = self.make_branch_builder('foobar')
 
62
        br = branch.Branch.open('foobar')
 
63
 
48
64
    def test_list_files(self):
49
65
        tree = self.make_branch_and_tree('.')
50
66
        self.build_tree(['dir/', 'file'])
195
211
        os.unlink('hello.txt')
196
212
        tree.remove('hello.txt')
197
213
        tree.revert(['hello.txt'])
198
 
        self.failUnlessExists('hello.txt')
 
214
        self.assertPathExists('hello.txt')
199
215
 
200
216
    def test_versioned_files_not_unknown(self):
201
217
        tree = self.make_branch_and_tree('.')
233
249
 
234
250
        wt.commit('create initial state')
235
251
 
236
 
        revid = b.revision_history()[0]
 
252
        revid = b.last_revision()
237
253
        self.log('first revision_id is {%s}' % revid)
238
254
 
239
 
        inv = b.repository.get_inventory(revid)
240
 
        self.log('contents of inventory: %r' % inv.entries())
 
255
        tree = b.repository.revision_tree(revid)
 
256
        self.log('contents of tree: %r' % list(tree.iter_entries_by_dir()))
241
257
 
242
 
        self.check_inventory_shape(inv,
243
 
                                   ['dir/', 'dir/sub/', 'dir/sub/file'])
 
258
        self.check_tree_shape(tree, ['dir/', 'dir/sub/', 'dir/sub/file'])
244
259
        wt.rename_one('dir', 'newdir')
245
260
 
246
261
        wt.lock_read()
247
 
        self.check_inventory_shape(wt.inventory,
 
262
        self.check_tree_shape(wt,
248
263
                                   ['newdir/', 'newdir/sub/', 'newdir/sub/file'])
249
264
        wt.unlock()
250
265
        wt.rename_one('newdir/sub', 'newdir/newsub')
251
266
        wt.lock_read()
252
 
        self.check_inventory_shape(wt.inventory,
253
 
                                   ['newdir/', 'newdir/newsub/',
 
267
        self.check_tree_shape(wt, ['newdir/', 'newdir/newsub/',
254
268
                                    'newdir/newsub/file'])
255
269
        wt.unlock()
256
270
 
264
278
        wt = self.make_branch_and_tree('.')
265
279
        self.build_tree(['foo/',
266
280
                         'foo/hello'])
267
 
        self.assertRaises(NotVersionedError,
268
 
                          wt.add,
269
 
                          'foo/hello')
 
281
        if not wt._format.supports_versioned_directories:
 
282
            wt.add('foo/hello')
 
283
        else:
 
284
            self.assertRaises(NotVersionedError,
 
285
                              wt.add,
 
286
                              'foo/hello')
270
287
 
271
288
    def test_add_missing(self):
272
289
        # adding a msising file -> NoSuchFile
295
312
        cloned = cloned_dir.open_workingtree()
296
313
        self.assertEqual(cloned.get_parent_ids(), wt.get_parent_ids())
297
314
 
 
315
    def test_clone_empty(self):
 
316
        wt = self.make_branch_and_tree('source')
 
317
        cloned_dir = wt.bzrdir.clone('target', revision_id=_mod_revision.NULL_REVISION)
 
318
        cloned = cloned_dir.open_workingtree()
 
319
        self.assertEqual(cloned.get_parent_ids(), wt.get_parent_ids())
 
320
 
298
321
    def test_last_revision(self):
299
322
        wt = self.make_branch_and_tree('source')
300
323
        self.assertEqual([], wt.get_parent_ids())
319
342
        # because some formats mutate the branch to set it on the tree
320
343
        # we need to alter the branch to let this pass.
321
344
        try:
322
 
            wt.branch.set_revision_history(['A', 'B'])
 
345
            self.applyDeprecated(symbol_versioning.deprecated_in((2, 4, 0)),
 
346
                wt.branch.set_revision_history, ['A', 'B'])
323
347
        except errors.NoSuchRevision, e:
324
348
            self.assertEqual('B', e.revision)
325
349
            raise TestSkipped("Branch format does not permit arbitrary"
390
414
        wt.set_parent_ids(['B'])
391
415
        tree = wt.basis_tree()
392
416
        tree.lock_read()
393
 
        self.failUnless(tree.has_filename('bar'))
 
417
        self.assertTrue(tree.has_filename('bar'))
394
418
        tree.unlock()
395
419
        wt.set_parent_ids(['A'])
396
420
        tree = wt.basis_tree()
397
421
        tree.lock_read()
398
 
        self.failUnless(tree.has_filename('foo'))
 
422
        self.assertTrue(tree.has_filename('foo'))
399
423
        tree.unlock()
400
424
 
401
425
    def test_clone_tree_revision(self):
456
480
        wt.commit('A', rev_id='A')
457
481
        # and update old_tree
458
482
        self.assertEqual(0, old_tree.update())
459
 
        self.failUnlessExists('checkout/file')
 
483
        self.assertPathExists('checkout/file')
460
484
        self.assertEqual(['A'], old_tree.get_parent_ids())
461
485
 
462
486
    def test_update_sets_root_id(self):
477
501
        wt.commit('A', rev_id='A')
478
502
        # and update checkout
479
503
        self.assertEqual(0, checkout.update())
480
 
        self.failUnlessExists('checkout/file')
 
504
        self.assertPathExists('checkout/file')
481
505
        self.assertEqual(wt.get_root_id(), checkout.get_root_id())
482
506
        self.assertNotEqual(None, wt.get_root_id())
483
507
 
558
582
            a.close()
559
583
        this.revert()
560
584
        self.assertFileEqual('a test\n', 'b1/a')
561
 
        self.failUnlessExists('b1/b.~1~')
562
 
        self.failIfExists('b1/c')
563
 
        self.failIfExists('b1/a.~1~')
564
 
        self.failUnlessExists('b1/d')
 
585
        self.assertPathExists('b1/b.~1~')
 
586
        self.assertPathDoesNotExist('b1/c')
 
587
        self.assertPathDoesNotExist('b1/a.~1~')
 
588
        self.assertPathExists('b1/d')
565
589
 
566
590
    def test_update_updates_bound_branch_no_local_commits(self):
567
591
        # doing an update in a tree updates the branch its bound to too.
605
629
        # which should have pivoted the local tip into a merge
606
630
        self.assertEqual([master_tip, 'bar'], tree.get_parent_ids())
607
631
        # and the local branch history should match the masters now.
608
 
        self.assertEqual(master_tree.branch.revision_history(),
609
 
            tree.branch.revision_history())
 
632
        self.assertEqual(master_tree.branch.last_revision(),
 
633
            tree.branch.last_revision())
610
634
 
611
635
    def test_update_takes_revision_parameter(self):
612
636
        wt = self.make_branch_and_tree('wt')
626
650
        # FIXME: This doesn't really test that it works; also this is not
627
651
        # implementation-independent. mbp 20070226
628
652
        tree = self.make_branch_and_tree('master')
 
653
        if not isinstance(tree, InventoryWorkingTree):
 
654
            raise TestNotApplicable("merge-hashes is specific to bzr "
 
655
                "working trees")
629
656
        tree._transport.put_bytes('merge-hashes', 'asdfasdf')
630
657
        self.assertRaises(errors.MergeModifiedFormatError, tree.merge_modified)
631
658
 
730
757
    def test_format_description(self):
731
758
        tree = self.make_branch_and_tree('tree')
732
759
        text = tree._format.get_format_description()
733
 
        self.failUnless(len(text))
 
760
        self.assertTrue(len(text))
734
761
 
735
762
    def test_branch_attribute_is_not_settable(self):
736
763
        # the branch attribute is an aspect of the working tree, not a
767
794
            tree.lock_read()
768
795
            self.assertEqual([('', 'directory'), (u'\xe5', 'file')],
769
796
                    [(path, ie.kind) for path,ie in
770
 
                                tree.inventory.iter_entries()])
 
797
                                tree.iter_entries_by_dir()])
771
798
            tree.unlock()
772
799
        finally:
773
800
            osutils.normalized_filename = orig
789
816
    def test__write_inventory(self):
790
817
        # The private interface _write_inventory is currently used by transform.
791
818
        tree = self.make_branch_and_tree('.')
 
819
        if not isinstance(tree, InventoryWorkingTree):
 
820
            raise TestNotApplicable("_write_inventory does not exist on "
 
821
                "non-inventory working trees")
792
822
        # if we write write an inventory then do a walkdirs we should get back
793
823
        # missing entries, and actual, and unknowns as appropriate.
794
824
        self.build_tree(['present', 'unknown'])
915
945
        else:
916
946
            case_sensitive = True
917
947
        tree = self.make_branch_and_tree('test')
918
 
        if tree.__class__ == WorkingTree2:
919
 
            raise TestSkipped('WorkingTree2 is not supported')
920
948
        self.assertEqual(case_sensitive, tree.case_sensitive)
 
949
        if not isinstance(tree, InventoryWorkingTree):
 
950
            raise TestNotApplicable("get_format_string is only available "
 
951
                                    "on bzr working trees")
 
952
        # now we cheat, and make a file that matches the case-sensitive name
 
953
        t = tree.bzrdir.get_workingtree_transport(None)
 
954
        try:
 
955
            content = tree._format.get_format_string()
 
956
        except NotImplementedError:
 
957
            # All-in-one formats didn't have a separate format string.
 
958
            content = tree.bzrdir._format.get_format_string()
 
959
        t.put_bytes(tree._format.case_sensitive_filename, content)
 
960
        tree = tree.bzrdir.open_workingtree()
 
961
        self.assertFalse(tree.case_sensitive)
921
962
 
922
963
    def test_all_file_ids_with_missing(self):
923
964
        tree = self.make_branch_and_tree('tree')
969
1010
            4 5-M
970
1011
            |
971
1012
            W
972
 
         """
973
 
        builder = branchbuilder.BranchBuilder(
974
 
            self.get_transport(),
975
 
            format=self.workingtree_format._matchingbzrdir)
 
1013
        """
 
1014
        format = self.workingtree_format.get_controldir_for_branch()
 
1015
        builder = self.make_branch_builder(".", format=format)
976
1016
        builder.start_series()
977
1017
        # mainline
978
1018
        builder.build_snapshot(
1054
1094
        self.assertEqual(0, wt.update(revision='1'))
1055
1095
        self.assertEqual('1', wt.last_revision())
1056
1096
        self.assertEqual(tip, wt.branch.last_revision())
1057
 
        self.failUnlessExists('checkout/file1')
1058
 
        self.failIfExists('checkout/file4')
1059
 
        self.failIfExists('checkout/file5')
 
1097
        self.assertPathExists('checkout/file1')
 
1098
        self.assertPathDoesNotExist('checkout/file4')
 
1099
        self.assertPathDoesNotExist('checkout/file5')
1060
1100
 
1061
1101
 
1062
1102
class TestIllegalPaths(TestCaseWithWorkingTree):
1065
1105
        if osutils.normalizes_filenames():
1066
1106
            # You *can't* create an illegal filename on OSX.
1067
1107
            raise tests.TestNotApplicable('OSX normalizes filenames')
1068
 
        self.requireFeature(tests.UTF8Filesystem)
 
1108
        self.requireFeature(features.UTF8Filesystem)
1069
1109
        # We require a UTF8 filesystem, because otherwise we would need to get
1070
1110
        # tricky to figure out how to create an illegal filename.
1071
1111
        # \xb5 is an illegal path because it should be \xc2\xb5 for UTF-8
1095
1135
 
1096
1136
class TestControlComponent(TestCaseWithWorkingTree):
1097
1137
    """WorkingTree implementations adequately implement ControlComponent."""
1098
 
    
 
1138
 
1099
1139
    def test_urls(self):
1100
1140
        wt = self.make_branch_and_tree('wt')
1101
1141
        self.assertIsInstance(wt.user_url, str)
1104
1144
        # above the control dir but we might need to relax that?
1105
1145
        self.assertEqual(wt.control_url.find(wt.user_url), 0)
1106
1146
        self.assertEqual(wt.control_url, wt.control_transport.base)
 
1147
 
 
1148
 
 
1149
class TestWorthSavingLimit(TestCaseWithWorkingTree):
 
1150
 
 
1151
    def make_wt_with_worth_saving_limit(self):
 
1152
        wt = self.make_branch_and_tree('wt')
 
1153
        if getattr(wt, '_worth_saving_limit', None) is None:
 
1154
            raise tests.TestNotApplicable('no _worth_saving_limit for'
 
1155
                                          ' this tree type')
 
1156
        wt.lock_write()
 
1157
        self.addCleanup(wt.unlock)
 
1158
        return wt
 
1159
 
 
1160
    def test_not_set(self):
 
1161
        # Default should be 10
 
1162
        wt = self.make_wt_with_worth_saving_limit()
 
1163
        self.assertEqual(10, wt._worth_saving_limit())
 
1164
        ds = wt.current_dirstate()
 
1165
        self.assertEqual(10, ds._worth_saving_limit)
 
1166
 
 
1167
    def test_set_in_branch(self):
 
1168
        wt = self.make_wt_with_worth_saving_limit()
 
1169
        conf = config.BranchStack(wt.branch)
 
1170
        conf.set('bzr.workingtree.worth_saving_limit', '20')
 
1171
        self.assertEqual(20, wt._worth_saving_limit())
 
1172
        ds = wt.current_dirstate()
 
1173
        self.assertEqual(10, ds._worth_saving_limit)
 
1174
 
 
1175
    def test_invalid(self):
 
1176
        wt = self.make_wt_with_worth_saving_limit()
 
1177
        conf = config.BranchStack(wt.branch)
 
1178
        conf.set('bzr.workingtree.worth_saving_limit', 'a')
 
1179
        # If the config entry is invalid, default to 10
 
1180
        warnings = []
 
1181
        def warning(*args):
 
1182
            warnings.append(args[0] % args[1:])
 
1183
        self.overrideAttr(trace, 'warning', warning)
 
1184
        self.assertEqual(10, wt._worth_saving_limit())
 
1185
        self.assertLength(1, warnings)
 
1186
        self.assertEquals('Value "a" is not valid for'
 
1187
                          ' "bzr.workingtree.worth_saving_limit"',
 
1188
                          warnings[0])
 
1189
 
 
1190
 
 
1191
class TestFormatAttributes(TestCaseWithWorkingTree):
 
1192
 
 
1193
    def test_versioned_directories(self):
 
1194
        self.assertSubset(
 
1195
            [self.workingtree_format.supports_versioned_directories],
 
1196
            (True, False))