~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

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

  • Committer: Robert Collins
  • Date: 2007-07-04 08:08:13 UTC
  • mfrom: (2572 +trunk)
  • mto: This revision was merged to the branch mainline in revision 2587.
  • Revision ID: robertc@robertcollins.net-20070704080813-wzebx0r88fvwj5rq
Merge bzr.dev.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2005, 2006 Canonical Ltd
 
1
# Copyright (C) 2005, 2006, 2007 Canonical Ltd
2
2
# Authors:  Robert Collins <robert.collins@canonical.com>
 
3
#           and others
3
4
#
4
5
# This program is free software; you can redistribute it and/or modify
5
6
# it under the terms of the GNU General Public License as published by
23
24
from bzrlib import branch, bzrdir, errors, osutils, urlutils, workingtree
24
25
from bzrlib.errors import (NotBranchError, NotVersionedError,
25
26
                           UnsupportedOperation, PathsNotVersionedError)
 
27
from bzrlib.inventory import Inventory
26
28
from bzrlib.osutils import pathjoin, getcwd, has_symlinks
27
29
from bzrlib.tests import TestSkipped
28
30
from bzrlib.tests.workingtree_implementations import TestCaseWithWorkingTree
40
42
        self.build_tree(['dir/', 'file'])
41
43
        if has_symlinks():
42
44
            os.symlink('target', 'symlink')
 
45
        tree.lock_read()
43
46
        files = list(tree.list_files())
 
47
        tree.unlock()
44
48
        self.assertEqual(files[0], ('dir', '?', 'directory', None, TreeDirectory()))
45
49
        self.assertEqual(files[1], ('file', '?', 'file', None, TreeFile()))
46
50
        if has_symlinks():
51
55
        self.build_tree(['dir/', 'file', 'dir/file', 'dir/b',
52
56
                         'dir/subdir/', 'a', 'dir/subfile',
53
57
                         'zz_dir/', 'zz_dir/subfile'])
 
58
        tree.lock_read()
54
59
        files = [(path, kind) for (path, v, kind, file_id, entry)
55
60
                               in tree.list_files()]
 
61
        tree.unlock()
56
62
        self.assertEqual([
57
63
            ('a', 'file'),
58
64
            ('dir', 'directory'),
61
67
            ], files)
62
68
 
63
69
        tree.add(['dir', 'zz_dir'])
 
70
        tree.lock_read()
64
71
        files = [(path, kind) for (path, v, kind, file_id, entry)
65
72
                               in tree.list_files()]
 
73
        tree.unlock()
66
74
        self.assertEqual([
67
75
            ('a', 'file'),
68
76
            ('dir', 'directory'),
75
83
            ('zz_dir/subfile', 'file'),
76
84
            ], files)
77
85
 
 
86
    def test_list_files_kind_change(self):
 
87
        tree = self.make_branch_and_tree('tree')
 
88
        self.build_tree(['tree/filename'])
 
89
        tree.add('filename', 'file-id')
 
90
        os.unlink('tree/filename')
 
91
        self.build_tree(['tree/filename/'])
 
92
        tree.lock_read()
 
93
        self.addCleanup(tree.unlock)
 
94
        result = list(tree.list_files())
 
95
        self.assertEqual(1, len(result))
 
96
        self.assertEqual(('filename', 'V', 'directory', 'file-id'),
 
97
                         result[0][:4])
 
98
 
78
99
    def test_open_containing(self):
79
100
        branch = self.make_branch_and_tree('.').branch
80
101
        local_base = urlutils.local_path_from_url(branch.base)
107
128
        self.assertEqual('foo', relpath)
108
129
        self.assertEqual(wt.basedir + '/', local_base)
109
130
 
110
 
 
111
131
    def test_basic_relpath(self):
112
132
        # for comprehensive relpath tests, see whitebox.py.
113
133
        tree = self.make_branch_and_tree('.')
212
232
        self.log('contents of inventory: %r' % inv.entries())
213
233
 
214
234
        self.check_inventory_shape(inv,
215
 
                                   ['dir', 'dir/sub', 'dir/sub/file'])
216
 
 
 
235
                                   ['dir/', 'dir/sub/', 'dir/sub/file'])
217
236
        wt.rename_one('dir', 'newdir')
218
237
 
219
 
        self.check_inventory_shape(wt.read_working_inventory(),
220
 
                                   ['newdir', 'newdir/sub', 'newdir/sub/file'])
221
 
 
 
238
        wt.lock_read()
 
239
        self.check_inventory_shape(wt.inventory,
 
240
                                   ['newdir/', 'newdir/sub/', 'newdir/sub/file'])
 
241
        wt.unlock()
222
242
        wt.rename_one('newdir/sub', 'newdir/newsub')
223
 
        self.check_inventory_shape(wt.read_working_inventory(),
224
 
                                   ['newdir', 'newdir/newsub',
 
243
        wt.lock_read()
 
244
        self.check_inventory_shape(wt.inventory,
 
245
                                   ['newdir/', 'newdir/newsub/',
225
246
                                    'newdir/newsub/file'])
 
247
        wt.unlock()
226
248
 
227
249
    def test_add_in_unversioned(self):
228
250
        """Try to add a file in an unversioned directory.
269
291
        wt = self.make_branch_and_tree('source')
270
292
        self.assertEqual([], wt.get_parent_ids())
271
293
        wt.commit('A', allow_pointless=True, rev_id='A')
272
 
        self.assertEqual(['A'], wt.get_parent_ids())
 
294
        parent_ids = wt.get_parent_ids()
 
295
        self.assertEqual(['A'], parent_ids)
 
296
        for parent_id in parent_ids:
 
297
            self.assertIsInstance(parent_id, str)
273
298
 
274
299
    def test_set_last_revision(self):
275
300
        wt = self.make_branch_and_tree('source')
285
310
        # and now we can set it to 'A'
286
311
        # because some formats mutate the branch to set it on the tree
287
312
        # we need to alter the branch to let this pass.
288
 
        wt.branch.set_revision_history(['A', 'B'])
 
313
        try:
 
314
            wt.branch.set_revision_history(['A', 'B'])
 
315
        except errors.NoSuchRevision, e:
 
316
            self.assertEqual('B', e.revision)
 
317
            raise TestSkipped("Branch format does not permit arbitrary"
 
318
                              " history")
289
319
        wt.set_last_revision('A')
290
320
        self.assertEqual(['A'], wt.get_parent_ids())
 
321
        self.assertRaises(errors.ReservedId, wt.set_last_revision, 'A:')
291
322
 
292
323
    def test_set_last_revision_different_to_branch(self):
293
324
        # working tree formats from the meta-dir format and newer support
325
356
 
326
357
    def test_clone_preserves_content(self):
327
358
        wt = self.make_branch_and_tree('source')
328
 
        self.build_tree(['added', 'deleted', 'notadded'], transport=wt.bzrdir.transport.clone('..'))
 
359
        self.build_tree(['added', 'deleted', 'notadded'],
 
360
                        transport=wt.bzrdir.transport.clone('..'))
329
361
        wt.add('deleted', 'deleted')
330
362
        wt.commit('add deleted')
331
363
        wt.remove('deleted')
349
381
        wt.commit('B', rev_id='B')
350
382
        wt.set_parent_ids(['B'])
351
383
        tree = wt.basis_tree()
 
384
        tree.lock_read()
352
385
        self.failUnless(tree.has_filename('bar'))
 
386
        tree.unlock()
353
387
        wt.set_parent_ids(['A'])
354
388
        tree = wt.basis_tree()
 
389
        tree.lock_read()
355
390
        self.failUnless(tree.has_filename('foo'))
 
391
        tree.unlock()
356
392
 
357
393
    def test_clone_tree_revision(self):
358
394
        # make a tree with a last-revision,
413
449
        self.failUnlessExists('checkout/file')
414
450
        self.assertEqual(['A'], old_tree.get_parent_ids())
415
451
 
 
452
    def test_update_sets_root_id(self):
 
453
        """Ensure tree root is set properly by update.
 
454
        
 
455
        Since empty trees don't have root_ids, but workingtrees do,
 
456
        an update of a checkout of revision 0 to a new revision,  should set
 
457
        the root id.
 
458
        """
 
459
        wt = self.make_branch_and_tree('tree')
 
460
        main_branch = wt.branch
 
461
        # create an out of date working tree by making a checkout in this
 
462
        # current format
 
463
        self.build_tree(['checkout/', 'tree/file'])
 
464
        checkout = main_branch.create_checkout('checkout')
 
465
        # now commit to 'tree'
 
466
        wt.add('file')
 
467
        wt.commit('A', rev_id='A')
 
468
        # and update checkout 
 
469
        self.assertEqual(0, checkout.update())
 
470
        self.failUnlessExists('checkout/file')
 
471
        self.assertEqual(wt.get_root_id(), checkout.get_root_id())
 
472
        self.assertNotEqual(None, wt.get_root_id())
 
473
 
416
474
    def test_update_returns_conflict_count(self):
417
475
        # working tree formats from the meta-dir format and newer support
418
476
        # setting the last revision on a tree independently of that on the 
517
575
        self.assertEqual(master_tree.branch.revision_history(),
518
576
            tree.branch.revision_history())
519
577
 
520
 
    def test_merge_modified(self):
 
578
    def test_merge_modified_detects_corruption(self):
 
579
        # FIXME: This doesn't really test that it works; also this is not
 
580
        # implementation-independent. mbp 20070226
521
581
        tree = self.make_branch_and_tree('master')
522
582
        tree._control_files.put('merge-hashes', StringIO('asdfasdf'))
523
583
        self.assertRaises(errors.MergeModifiedFormatError, tree.merge_modified)
524
584
 
 
585
    def test_merge_modified(self):
 
586
        # merge_modified stores a map from file id to hash
 
587
        tree = self.make_branch_and_tree('tree')
 
588
        d = {'file-id': osutils.sha_string('hello')}
 
589
        self.build_tree_contents([('tree/somefile', 'hello')])
 
590
        tree.lock_write()
 
591
        try:
 
592
            tree.add(['somefile'], ['file-id'])
 
593
            tree.set_merge_modified(d)
 
594
            mm = tree.merge_modified()
 
595
            self.assertEquals(mm, d)
 
596
        finally:
 
597
            tree.unlock()
 
598
        mm = tree.merge_modified()
 
599
        self.assertEquals(mm, d)
 
600
 
525
601
    def test_conflicts(self):
526
602
        from bzrlib.tests.test_conflicts import example_conflicts
527
603
        tree = self.make_branch_and_tree('master')
540
616
                          tree2.conflicts)
541
617
 
542
618
    def make_merge_conflicts(self):
543
 
        from bzrlib.merge import merge_inner 
 
619
        from bzrlib.merge import merge_inner
544
620
        tree = self.make_branch_and_tree('mine')
545
621
        file('mine/bloo', 'wb').write('one')
546
 
        tree.add('bloo')
547
622
        file('mine/blo', 'wb').write('on')
548
 
        tree.add('blo')
 
623
        tree.add(['bloo', 'blo'])
549
624
        tree.commit("blah", allow_pointless=False)
550
 
        base = tree.basis_tree()
 
625
        base = tree.branch.repository.revision_tree(tree.last_revision())
551
626
        bzrdir.BzrDir.open("mine").sprout("other")
552
627
        file('other/bloo', 'wb').write('two')
553
628
        othertree = WorkingTree.open('other')
625
700
        # ensure that foo.pyc is ignored
626
701
        self.build_tree_contents([('.bzrignore', 'foo.pyc')])
627
702
        tree.add('foo.pyc', 'anid')
 
703
        tree.lock_read()
628
704
        files = sorted(list(tree.list_files()))
 
705
        tree.unlock()
629
706
        self.assertEqual((u'.bzrignore', '?', 'file', None), files[0][:-1])
630
707
        self.assertEqual((u'foo.pyc', 'V', 'file', 'anid'), files[1][:-1])
631
708
        self.assertEqual(2, len(files))
640
717
        osutils.normalized_filename = osutils._accessible_normalized_filename
641
718
        try:
642
719
            tree.add([u'a\u030a'])
 
720
            tree.lock_read()
643
721
            self.assertEqual([('', 'directory'), (u'\xe5', 'file')],
644
722
                    [(path, ie.kind) for path,ie in 
645
723
                                tree.inventory.iter_entries()])
 
724
            tree.unlock()
646
725
        finally:
647
726
            osutils.normalized_filename = orig
648
727
 
659
738
                tree.add, [u'a\u030a'])
660
739
        finally:
661
740
            osutils.normalized_filename = orig
 
741
 
 
742
    def test__write_inventory(self):
 
743
        # The private interface _write_inventory is currently used by transform.
 
744
        tree = self.make_branch_and_tree('.')
 
745
        # if we write write an inventory then do a walkdirs we should get back
 
746
        # missing entries, and actual, and unknowns as appropriate.
 
747
        self.build_tree(['present', 'unknown'])
 
748
        inventory = Inventory(tree.path2id(''))
 
749
        inventory.add_path('missing', 'file', 'missing-id')
 
750
        inventory.add_path('present', 'file', 'present-id')
 
751
        # there is no point in being able to write an inventory to an unlocked
 
752
        # tree object - its a low level api not a convenience api.
 
753
        tree.lock_write()
 
754
        tree._write_inventory(inventory)
 
755
        tree.unlock()
 
756
        tree.lock_read()
 
757
        try:
 
758
            present_stat = os.lstat('present')
 
759
            unknown_stat = os.lstat('unknown')
 
760
            expected_results = [
 
761
                (('', tree.inventory.root.file_id),
 
762
                 [('missing', 'missing', 'unknown', None, 'missing-id', 'file'),
 
763
                  ('present', 'present', 'file', present_stat, 'present-id', 'file'),
 
764
                  ('unknown', 'unknown', 'file', unknown_stat, None, None),
 
765
                 ]
 
766
                )]
 
767
            self.assertEqual(expected_results, list(tree.walkdirs()))
 
768
        finally:
 
769
            tree.unlock()
 
770
 
 
771
    def test_path2id(self):
 
772
        # smoke test for path2id
 
773
        tree = self.make_branch_and_tree('.')
 
774
        self.build_tree(['foo'])
 
775
        tree.add(['foo'], ['foo-id'])
 
776
        self.assertEqual('foo-id', tree.path2id('foo'))
 
777
        # the next assertion is for backwards compatability with WorkingTree3,
 
778
        # though its probably a bad idea, it makes things work. Perhaps
 
779
        # it should raise a deprecation warning?
 
780
        self.assertEqual('foo-id', tree.path2id('foo/'))
 
781
 
 
782
    def test_filter_unversioned_files(self):
 
783
        # smoke test for filter_unversioned_files
 
784
        tree = self.make_branch_and_tree('.')
 
785
        paths = ['here-and-versioned', 'here-and-not-versioned',
 
786
            'not-here-and-versioned', 'not-here-and-not-versioned']
 
787
        tree.add(['here-and-versioned', 'not-here-and-versioned'],
 
788
            kinds=['file', 'file'])
 
789
        self.build_tree(['here-and-versioned', 'here-and-not-versioned'])
 
790
        tree.lock_read()
 
791
        self.addCleanup(tree.unlock)
 
792
        self.assertEqual(
 
793
            set(['not-here-and-not-versioned', 'here-and-not-versioned']),
 
794
            tree.filter_unversioned_files(paths))
 
795
 
 
796
    def test_detect_real_kind(self):
 
797
        # working trees report the real kind of the file on disk, not the kind
 
798
        # they had when they were first added
 
799
        # create one file of every interesting type
 
800
        tree = self.make_branch_and_tree('.')
 
801
        self.build_tree(['file', 'directory/'])
 
802
        names = ['file', 'directory']
 
803
        if has_symlinks():
 
804
            os.symlink('target', 'symlink')
 
805
            names.append('symlink')
 
806
        tree.add(names, [n + '-id' for n in names])
 
807
        if tree.supports_tree_reference():
 
808
            sub_tree = self.make_branch_and_tree('tree-reference')
 
809
            sub_tree.set_root_id('tree-reference-id')
 
810
            sub_tree.commit('message')
 
811
            names.append('tree-reference')
 
812
            tree.add_reference(sub_tree)
 
813
        # now when we first look, we should see everything with the same kind
 
814
        # with which they were initially added
 
815
        for n in names:
 
816
            actual_kind = tree.kind(n + '-id')
 
817
            self.assertEqual(n, actual_kind)
 
818
        # move them around so the names no longer correspond to the types
 
819
        os.rename(names[0], 'tmp')
 
820
        for i in range(1, len(names)):
 
821
            os.rename(names[i], names[i-1])
 
822
        os.rename('tmp', names[-1])
 
823
        # now look and expect to see the correct types again
 
824
        for i in range(len(names)):
 
825
            actual_kind = tree.kind(names[i-1] + '-id')
 
826
            expected_kind = names[i]
 
827
            self.assertEqual(expected_kind, actual_kind)
 
828
 
 
829
    def test_missing_file_sha1(self):
 
830
        """If a file is missing, its sha1 should be reported as None."""
 
831
        tree = self.make_branch_and_tree('.')
 
832
        tree.lock_write()
 
833
        self.addCleanup(tree.unlock)
 
834
        self.build_tree(['file'])
 
835
        tree.add('file', 'file-id')
 
836
        tree.commit('file added')
 
837
        os.unlink('file')
 
838
        self.assertIs(None, tree.get_file_sha1('file-id'))