~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/test_workingtree.py

Nearly complete .bzr/checkout splitout.

Show diffs side-by-side

added added

removed removed

Lines of Context:
20
20
 
21
21
import bzrlib
22
22
from bzrlib.branch import Branch
 
23
import bzrlib.bzrdir as bzrdir
23
24
from bzrlib.bzrdir import BzrDir
24
25
import bzrlib.errors as errors
25
26
from bzrlib.errors import NotBranchError, NotVersionedError
 
27
from bzrlib.osutils import pathjoin, getcwd, has_symlinks
26
28
from bzrlib.tests import TestCaseWithTransport
27
29
from bzrlib.trace import mutter
28
 
from bzrlib.osutils import pathjoin, getcwd, has_symlinks
 
30
from bzrlib.transport import get_transport
 
31
import bzrlib.workingtree as workingtree
29
32
from bzrlib.workingtree import (TreeEntry, TreeDirectory, TreeFile, TreeLink,
30
33
                                WorkingTree)
31
34
 
53
56
        self.assertEqual(TreeLink().kind_character(), '')
54
57
 
55
58
 
56
 
class TestWorkingTree(TestCaseWithTransport):
57
 
 
58
 
    def test_listfiles(self):
59
 
        tree = WorkingTree.create_standalone('.')
60
 
        os.mkdir('dir')
61
 
        print >> open('file', 'w'), "content"
62
 
        if has_symlinks():
63
 
            os.symlink('target', 'symlink')
64
 
        files = list(tree.list_files())
65
 
        self.assertEqual(files[0], ('dir', '?', 'directory', None, TreeDirectory()))
66
 
        self.assertEqual(files[1], ('file', '?', 'file', None, TreeFile()))
67
 
        if has_symlinks():
68
 
            self.assertEqual(files[2], ('symlink', '?', 'symlink', None, TreeLink()))
69
 
 
70
 
    def test_open_containing(self):
71
 
        branch = WorkingTree.create_standalone('.').branch
72
 
        wt, relpath = WorkingTree.open_containing()
73
 
        self.assertEqual('', relpath)
74
 
        self.assertEqual(wt.basedir + '/', branch.base)
75
 
        wt, relpath = WorkingTree.open_containing(u'.')
76
 
        self.assertEqual('', relpath)
77
 
        self.assertEqual(wt.basedir + '/', branch.base)
78
 
        wt, relpath = WorkingTree.open_containing('./foo')
79
 
        self.assertEqual('foo', relpath)
80
 
        self.assertEqual(wt.basedir + '/', branch.base)
81
 
        # paths that are urls are just plain wrong for working trees.
 
59
class TestDefaultFormat(TestCaseWithTransport):
 
60
 
 
61
    def test_get_set_default_format(self):
 
62
        old_format = workingtree.WorkingTreeFormat.get_default_format()
 
63
        # default is 3
 
64
        self.assertTrue(isinstance(old_format, workingtree.WorkingTreeFormat3))
 
65
        workingtree.WorkingTreeFormat.set_default_format(SampleTreeFormat())
 
66
        try:
 
67
            # the default branch format is used by the meta dir format
 
68
            # which is not the default bzrdir format at this point
 
69
            dir = bzrdir.BzrDirMetaFormat1().initialize('.')
 
70
            dir.create_repository()
 
71
            dir.create_branch()
 
72
            result = dir.create_workingtree()
 
73
            self.assertEqual(result, 'A tree')
 
74
        finally:
 
75
            workingtree.WorkingTreeFormat.set_default_format(old_format)
 
76
        self.assertEqual(old_format, workingtree.WorkingTreeFormat.get_default_format())
 
77
 
 
78
 
 
79
class SampleTreeFormat(workingtree.WorkingTreeFormat):
 
80
    """A sample format
 
81
 
 
82
    this format is initializable, unsupported to aid in testing the 
 
83
    open and open_downlevel routines.
 
84
    """
 
85
 
 
86
    def get_format_string(self):
 
87
        """See WorkingTreeFormat.get_format_string()."""
 
88
        return "Sample tree format."
 
89
 
 
90
    def initialize(self, a_bzrdir):
 
91
        """Sample branches cannot be created."""
 
92
        t = a_bzrdir.get_workingtree_transport(self)
 
93
        t.put('format', StringIO(self.get_format_string()))
 
94
        return 'A tree'
 
95
 
 
96
    def is_supported(self):
 
97
        return False
 
98
 
 
99
    def open(self, transport, _found=False):
 
100
        return "opened tree."
 
101
 
 
102
 
 
103
class TestWorkingTreeFormat(TestCaseWithTransport):
 
104
    """Tests for the WorkingTreeFormat facility."""
 
105
 
 
106
    def test_find_format(self):
 
107
        # is the right format object found for a working tree?
 
108
        # create a branch with a few known format objects.
 
109
        self.build_tree(["foo/", "bar/"])
 
110
        def check_format(format, url):
 
111
            dir = format._matchingbzrdir.initialize(url)
 
112
            dir.create_repository()
 
113
            dir.create_branch()
 
114
            format.initialize(dir)
 
115
            t = get_transport(url)
 
116
            found_format = workingtree.WorkingTreeFormat.find_format(dir)
 
117
            self.failUnless(isinstance(found_format, format.__class__))
 
118
        check_format(workingtree.WorkingTreeFormat3(), "bar")
 
119
        
 
120
    def test_find_format_no_tree(self):
 
121
        dir = bzrdir.BzrDirMetaFormat1().initialize('.')
82
122
        self.assertRaises(NotBranchError,
83
 
                          WorkingTree.open_containing, 
84
 
                          'file:///' + getcwd())
85
 
 
86
 
    def test_construct_with_branch(self):
87
 
        branch = WorkingTree.create_standalone('.').branch
88
 
        tree = WorkingTree(branch.base, branch)
89
 
        self.assertEqual(branch, tree.branch)
90
 
        self.assertEqual(branch.base, tree.basedir + '/')
91
 
    
92
 
    def test_construct_without_branch(self):
93
 
        branch = WorkingTree.create_standalone('.').branch
94
 
        tree = WorkingTree(branch.base)
95
 
        self.assertEqual(branch.base, tree.branch.base)
96
 
        self.assertEqual(branch.base, tree.basedir + '/')
97
 
 
98
 
    def test_basic_relpath(self):
99
 
        # for comprehensive relpath tests, see whitebox.py.
100
 
        tree = WorkingTree.create_standalone('.')
101
 
        self.assertEqual('child',
102
 
                         tree.relpath(pathjoin(getcwd(), 'child')))
103
 
 
104
 
    def test_lock_locks_branch(self):
105
 
        tree = WorkingTree.create_standalone('.')
106
 
        tree.lock_read()
107
 
        self.assertEqual('r', tree.branch.peek_lock_mode())
108
 
        tree.unlock()
109
 
        self.assertEqual(None, tree.branch.peek_lock_mode())
110
 
        tree.lock_write()
111
 
        self.assertEqual('w', tree.branch.peek_lock_mode())
112
 
        tree.unlock()
113
 
        self.assertEqual(None, tree.branch.peek_lock_mode())
114
 
 
115
 
    def get_pullable_trees(self):
116
 
        self.build_tree(['from/', 'from/file', 'to/'])
117
 
        tree = WorkingTree.create_standalone('from')
118
 
        tree.add('file')
119
 
        tree.commit('foo', rev_id='A')
120
 
        tree_b = WorkingTree.create_standalone('to')
121
 
        return tree, tree_b
122
 
 
123
 
    def test_pull(self):
124
 
        tree_a, tree_b = self.get_pullable_trees()
125
 
        tree_b.pull(tree_a.branch)
126
 
        self.failUnless(tree_b.branch.repository.has_revision('A'))
127
 
        self.assertEqual(['A'], tree_b.branch.revision_history())
128
 
 
129
 
    def test_pull_overwrites(self):
130
 
        tree_a, tree_b = self.get_pullable_trees()
131
 
        tree_b.commit('foo', rev_id='B')
132
 
        self.assertEqual(['B'], tree_b.branch.revision_history())
133
 
        tree_b.pull(tree_a.branch, overwrite=True)
134
 
        self.failUnless(tree_b.branch.repository.has_revision('A'))
135
 
        self.failUnless(tree_b.branch.repository.has_revision('B'))
136
 
        self.assertEqual(['A'], tree_b.branch.revision_history())
137
 
 
138
 
    def test_revert(self):
139
 
        """Test selected-file revert"""
140
 
        tree = WorkingTree.create_standalone('.')
141
 
 
142
 
        self.build_tree(['hello.txt'])
143
 
        file('hello.txt', 'w').write('initial hello')
144
 
 
145
 
        self.assertRaises(NotVersionedError,
146
 
                          tree.revert, ['hello.txt'])
147
 
        tree.add(['hello.txt'])
148
 
        tree.commit('create initial hello.txt')
149
 
 
150
 
        self.check_file_contents('hello.txt', 'initial hello')
151
 
        file('hello.txt', 'w').write('new hello')
152
 
        self.check_file_contents('hello.txt', 'new hello')
153
 
 
154
 
        # revert file modified since last revision
155
 
        tree.revert(['hello.txt'])
156
 
        self.check_file_contents('hello.txt', 'initial hello')
157
 
        self.check_file_contents('hello.txt~', 'new hello')
158
 
 
159
 
        # reverting again does not clobber the backup
160
 
        tree.revert(['hello.txt'])
161
 
        self.check_file_contents('hello.txt', 'initial hello')
162
 
        self.check_file_contents('hello.txt~', 'new hello')
163
 
 
164
 
    def test_unknowns(self):
165
 
        tree = WorkingTree.create_standalone('.')
166
 
        self.build_tree(['hello.txt',
167
 
                         'hello.txt~'])
168
 
        self.assertEquals(list(tree.unknowns()),
169
 
                          ['hello.txt'])
170
 
 
171
 
    def test_hashcache(self):
172
 
        from bzrlib.tests.test_hashcache import pause
173
 
        tree = WorkingTree.create_standalone('.')
174
 
        self.build_tree(['hello.txt',
175
 
                         'hello.txt~'])
176
 
        tree.add('hello.txt')
177
 
        pause()
178
 
        sha = tree.get_file_sha1(tree.path2id('hello.txt'))
179
 
        self.assertEqual(1, tree._hashcache.miss_count)
180
 
        tree2 = WorkingTree('.', tree.branch)
181
 
        sha2 = tree2.get_file_sha1(tree2.path2id('hello.txt'))
182
 
        self.assertEqual(0, tree2._hashcache.miss_count)
183
 
        self.assertEqual(1, tree2._hashcache.hit_count)
184
 
 
185
 
    def test_checkout(self):
186
 
        # at this point as we dont have checkout versions, checkout simply
187
 
        # populates the required files for a working tree at the dir.
188
 
        b = BzrDir.create_branch_and_repo('branch')
189
 
        t = WorkingTree.create(b, 'tree')
190
 
        # as we are moving the ownership to working tree, we will check here
191
 
        # that its split out correctly
192
 
        self.failIfExists('branch/.bzr/inventory')
193
 
        self.failIfExists('branch/.bzr/pending-merges')
194
 
        sio = StringIO()
195
 
        bzrlib.xml5.serializer_v5.write_inventory(bzrlib.inventory.Inventory(),
196
 
                                                  sio)
197
 
        self.assertFileEqual(sio.getvalue(), 'tree/.bzr/inventory')
198
 
        self.assertFileEqual('', 'tree/.bzr/pending-merges')
199
 
 
200
 
    def test_initialize(self):
201
 
        # initialize should create a working tree and branch in an existing dir
202
 
        t = WorkingTree.create_standalone('.')
203
 
        b = Branch.open('.')
204
 
        self.assertEqual(t.branch.base, b.base)
205
 
        t2 = WorkingTree('.')
206
 
        self.assertEqual(t.basedir, t2.basedir)
207
 
        self.assertEqual(b.base, t2.branch.base)
208
 
        # TODO maybe we should check the branch format? not sure if its
209
 
        # appropriate here.
210
 
 
211
 
    def test_rename_dirs(self):
212
 
        """Test renaming directories and the files within them."""
213
 
        wt = self.make_branch_and_tree('.')
214
 
        b = wt.branch
215
 
        self.build_tree(['dir/', 'dir/sub/', 'dir/sub/file'])
216
 
        wt.add(['dir', 'dir/sub', 'dir/sub/file'])
217
 
 
218
 
        wt.commit('create initial state')
219
 
 
220
 
        revid = b.revision_history()[0]
221
 
        self.log('first revision_id is {%s}' % revid)
222
 
        
223
 
        inv = b.repository.get_revision_inventory(revid)
224
 
        self.log('contents of inventory: %r' % inv.entries())
225
 
 
226
 
        self.check_inventory_shape(inv,
227
 
                                   ['dir', 'dir/sub', 'dir/sub/file'])
228
 
 
229
 
        wt.rename_one('dir', 'newdir')
230
 
 
231
 
        self.check_inventory_shape(wt.read_working_inventory(),
232
 
                                   ['newdir', 'newdir/sub', 'newdir/sub/file'])
233
 
 
234
 
        wt.rename_one('newdir/sub', 'newdir/newsub')
235
 
        self.check_inventory_shape(wt.read_working_inventory(),
236
 
                                   ['newdir', 'newdir/newsub',
237
 
                                    'newdir/newsub/file'])
238
 
 
239
 
    def test_add_in_unversioned(self):
240
 
        """Try to add a file in an unversioned directory.
241
 
 
242
 
        "bzr add" adds the parent as necessary, but simple working tree add
243
 
        doesn't do that.
244
 
        """
245
 
        from bzrlib.errors import NotVersionedError
246
 
        wt = self.make_branch_and_tree('.')
247
 
        self.build_tree(['foo/',
248
 
                         'foo/hello'])
249
 
        self.assertRaises(NotVersionedError,
250
 
                          wt.add,
251
 
                          'foo/hello')
252
 
 
253
 
    def test_add_missing(self):
254
 
        # adding a msising file -> NoSuchFile
255
 
        wt = self.make_branch_and_tree('.')
256
 
        self.assertRaises(errors.NoSuchFile, wt.add, 'fpp')
257
 
 
258
 
    def test_remove_verbose(self):
259
 
        #FIXME the remove api should not print or otherwise depend on the
260
 
        # text UI - RBC 20060124
261
 
        wt = self.make_branch_and_tree('.')
262
 
        self.build_tree(['hello'])
263
 
        wt.add(['hello'])
264
 
        wt.commit(message='add hello')
265
 
        stdout = StringIO()
266
 
        stderr = StringIO()
267
 
        self.assertEqual(None, self.apply_redirected(None, stdout, stderr,
268
 
                                                     wt.remove,
269
 
                                                     ['hello'],
270
 
                                                     verbose=True))
271
 
        self.assertEqual('?       hello\n', stdout.getvalue())
272
 
        self.assertEqual('', stderr.getvalue())
273
 
 
274
 
    def test_clone_trivial(self):
275
 
        wt = self.make_branch_and_tree('source')
276
 
        cloned = wt.clone('target')
277
 
        self.assertEqual(cloned.last_revision(), wt.last_revision())
278
 
 
279
 
    def test_last_revision(self):
280
 
        wt = self.make_branch_and_tree('source')
281
 
        self.assertEqual(None, wt.last_revision())
282
 
        wt.commit('A', allow_pointless=True, rev_id='A')
283
 
        self.assertEqual('A', wt.last_revision())
284
 
 
285
 
    def test_set_last_revision(self):
286
 
        wt = self.make_branch_and_tree('source')
287
 
        self.assertEqual(None, wt.last_revision())
288
 
        # cannot set the last revision to one not in the branch
289
 
        self.assertRaises(errors.NoSuchRevision, wt.set_last_revision, 'A')
290
 
        wt.commit('A', allow_pointless=True, rev_id='A')
291
 
        self.assertEqual('A', wt.last_revision())
292
 
        # None is aways in the branch
293
 
        wt.set_last_revision(None)
294
 
        self.assertEqual(None, wt.last_revision())
295
 
        # and now we can set it to 'A'
296
 
        # because the current format mutates the branch to set it,
297
 
        # we need to alter the branch to let this pass.
298
 
        wt.branch.set_revision_history(['A', 'B'])
299
 
        wt.set_last_revision('A')
300
 
        self.assertEqual('A', wt.last_revision())
301
 
 
302
 
    def test_clone_and_commit_preserves_last_revision(self):
303
 
        wt = self.make_branch_and_tree('source')
304
 
        cloned = wt.clone('target')
305
 
        wt.commit('A', allow_pointless=True, rev_id='A')
306
 
        self.assertNotEqual(cloned.last_revision(), wt.last_revision())
307
 
        
308
 
    def test_basis_tree_returns_last_revision(self):
309
 
        wt = self.make_branch_and_tree('.')
310
 
        self.build_tree(['foo'])
311
 
        wt.add('foo', 'foo-id')
312
 
        wt.commit('A', rev_id='A')
313
 
        wt.rename_one('foo', 'bar')
314
 
        wt.commit('B', rev_id='B')
315
 
        wt.set_last_revision('B')
316
 
        tree = wt.basis_tree()
317
 
        self.failUnless(tree.has_filename('bar'))
318
 
        wt.set_last_revision('A')
319
 
        tree = wt.basis_tree()
320
 
        self.failUnless(tree.has_filename('foo'))
 
123
                          workingtree.WorkingTreeFormat.find_format,
 
124
                          dir)
 
125
 
 
126
    def test_find_format_unknown_format(self):
 
127
        dir = bzrdir.BzrDirMetaFormat1().initialize('.')
 
128
        dir.create_repository()
 
129
        dir.create_branch()
 
130
        SampleTreeFormat().initialize(dir)
 
131
        self.assertRaises(errors.UnknownFormatError,
 
132
                          workingtree.WorkingTreeFormat.find_format,
 
133
                          dir)
 
134
 
 
135
    def test_register_unregister_format(self):
 
136
        format = SampleTreeFormat()
 
137
        # make a control dir
 
138
        dir = bzrdir.BzrDirMetaFormat1().initialize('.')
 
139
        dir.create_repository()
 
140
        dir.create_branch()
 
141
        # make a branch
 
142
        format.initialize(dir)
 
143
        # register a format for it.
 
144
        workingtree.WorkingTreeFormat.register_format(format)
 
145
        # which branch.Open will refuse (not supported)
 
146
        self.assertRaises(errors.UnsupportedFormatError, workingtree.WorkingTree.open, '.')
 
147
        # compatability
 
148
        self.assertRaises(errors.UnsupportedFormatError, workingtree.WorkingTree, '.')
 
149
        # but open_downlevel will work
 
150
        self.assertEqual(format.open(dir), workingtree.WorkingTree.open_downlevel('.'))
 
151
        # unregister the format
 
152
        workingtree.WorkingTreeFormat.unregister_format(format)