/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar
1534.4.46 by Robert Collins
Nearly complete .bzr/checkout splitout.
1
# (C) 2005,2006 Canonical Ltd
2
# Authors:  Robert Collins <robert.collins@canonical.com>
3
#
4
# This program is free software; you can redistribute it and/or modify
5
# it under the terms of the GNU General Public License as published by
6
# the Free Software Foundation; either version 2 of the License, or
7
# (at your option) any later version.
8
#
9
# This program is distributed in the hope that it will be useful,
10
# but WITHOUT ANY WARRANTY; without even the implied warranty of
11
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
# GNU General Public License for more details.
13
#
14
# You should have received a copy of the GNU General Public License
15
# along with this program; if not, write to the Free Software
16
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
17
18
from cStringIO import StringIO
19
import os
20
21
import bzrlib
1508.1.25 by Robert Collins
Update per review comments.
22
import bzrlib.branch
1534.4.46 by Robert Collins
Nearly complete .bzr/checkout splitout.
23
from bzrlib.branch import Branch
24
import bzrlib.bzrdir as bzrdir
25
from bzrlib.bzrdir import BzrDir
26
import bzrlib.errors as errors
1534.10.8 by Aaron Bentley
Implemented conflict_lines in terms of old system on WorkingTree
27
from bzrlib.errors import (NotBranchError, NotVersionedError, 
28
                           UnsupportedOperation)
1685.1.45 by John Arbash Meinel
Moved url functions into bzrlib.urlutils
29
from bzrlib.osutils import pathjoin, getcwd, has_symlinks
1534.5.5 by Robert Collins
Move is_control_file into WorkingTree.is_control_filename and test.
30
from bzrlib.tests import TestSkipped
31
from bzrlib.tests.workingtree_implementations import TestCaseWithWorkingTree
1534.4.46 by Robert Collins
Nearly complete .bzr/checkout splitout.
32
from bzrlib.trace import mutter
1685.1.45 by John Arbash Meinel
Moved url functions into bzrlib.urlutils
33
import bzrlib.urlutils as urlutils
1534.4.46 by Robert Collins
Nearly complete .bzr/checkout splitout.
34
import bzrlib.workingtree as workingtree
35
from bzrlib.workingtree import (TreeEntry, TreeDirectory, TreeFile, TreeLink,
36
                                WorkingTree)
37
38
39
class TestWorkingTree(TestCaseWithWorkingTree):
40
41
    def test_listfiles(self):
42
        tree = self.make_branch_and_tree('.')
43
        os.mkdir('dir')
44
        print >> open('file', 'w'), "content"
45
        if has_symlinks():
46
            os.symlink('target', 'symlink')
47
        files = list(tree.list_files())
48
        self.assertEqual(files[0], ('dir', '?', 'directory', None, TreeDirectory()))
49
        self.assertEqual(files[1], ('file', '?', 'file', None, TreeFile()))
50
        if has_symlinks():
51
            self.assertEqual(files[2], ('symlink', '?', 'symlink', None, TreeLink()))
52
53
    def test_open_containing(self):
1534.4.50 by Robert Collins
Got the bzrdir api straightened out, plenty of refactoring to use it pending, but the api is up and running.
54
        branch = self.make_branch_and_tree('.').branch
1534.4.46 by Robert Collins
Nearly complete .bzr/checkout splitout.
55
        wt, relpath = WorkingTree.open_containing()
56
        self.assertEqual('', relpath)
1685.1.45 by John Arbash Meinel
Moved url functions into bzrlib.urlutils
57
        self.assertEqual(wt.basedir + '/', urlutils.local_path_from_url(branch.base))
1534.4.46 by Robert Collins
Nearly complete .bzr/checkout splitout.
58
        wt, relpath = WorkingTree.open_containing(u'.')
59
        self.assertEqual('', relpath)
1685.1.45 by John Arbash Meinel
Moved url functions into bzrlib.urlutils
60
        self.assertEqual(wt.basedir + '/', urlutils.local_path_from_url(branch.base))
1534.4.46 by Robert Collins
Nearly complete .bzr/checkout splitout.
61
        wt, relpath = WorkingTree.open_containing('./foo')
62
        self.assertEqual('foo', relpath)
1685.1.45 by John Arbash Meinel
Moved url functions into bzrlib.urlutils
63
        self.assertEqual(wt.basedir + '/', urlutils.local_path_from_url(branch.base))
1534.4.46 by Robert Collins
Nearly complete .bzr/checkout splitout.
64
        wt, relpath = WorkingTree.open_containing('file://' + getcwd() + '/foo')
65
        self.assertEqual('foo', relpath)
1685.1.45 by John Arbash Meinel
Moved url functions into bzrlib.urlutils
66
        self.assertEqual(wt.basedir + '/', urlutils.local_path_from_url(branch.base))
1534.4.46 by Robert Collins
Nearly complete .bzr/checkout splitout.
67
68
    def test_basic_relpath(self):
69
        # for comprehensive relpath tests, see whitebox.py.
1534.4.50 by Robert Collins
Got the bzrdir api straightened out, plenty of refactoring to use it pending, but the api is up and running.
70
        tree = self.make_branch_and_tree('.')
1534.4.46 by Robert Collins
Nearly complete .bzr/checkout splitout.
71
        self.assertEqual('child',
72
                         tree.relpath(pathjoin(getcwd(), 'child')))
73
74
    def test_lock_locks_branch(self):
1534.4.50 by Robert Collins
Got the bzrdir api straightened out, plenty of refactoring to use it pending, but the api is up and running.
75
        tree = self.make_branch_and_tree('.')
1534.4.46 by Robert Collins
Nearly complete .bzr/checkout splitout.
76
        tree.lock_read()
77
        self.assertEqual('r', tree.branch.peek_lock_mode())
78
        tree.unlock()
79
        self.assertEqual(None, tree.branch.peek_lock_mode())
80
        tree.lock_write()
81
        self.assertEqual('w', tree.branch.peek_lock_mode())
82
        tree.unlock()
83
        self.assertEqual(None, tree.branch.peek_lock_mode())
84
 
85
    def test_revert(self):
86
        """Test selected-file revert"""
1534.4.50 by Robert Collins
Got the bzrdir api straightened out, plenty of refactoring to use it pending, but the api is up and running.
87
        tree = self.make_branch_and_tree('.')
1534.4.46 by Robert Collins
Nearly complete .bzr/checkout splitout.
88
89
        self.build_tree(['hello.txt'])
90
        file('hello.txt', 'w').write('initial hello')
91
92
        self.assertRaises(NotVersionedError,
93
                          tree.revert, ['hello.txt'])
94
        tree.add(['hello.txt'])
95
        tree.commit('create initial hello.txt')
96
97
        self.check_file_contents('hello.txt', 'initial hello')
98
        file('hello.txt', 'w').write('new hello')
99
        self.check_file_contents('hello.txt', 'new hello')
100
101
        # revert file modified since last revision
102
        tree.revert(['hello.txt'])
103
        self.check_file_contents('hello.txt', 'initial hello')
1534.10.29 by Aaron Bentley
Fixed backup numbering to match GNU standard better
104
        self.check_file_contents('hello.txt.~1~', 'new hello')
1534.4.46 by Robert Collins
Nearly complete .bzr/checkout splitout.
105
106
        # reverting again does not clobber the backup
107
        tree.revert(['hello.txt'])
108
        self.check_file_contents('hello.txt', 'initial hello')
1534.10.29 by Aaron Bentley
Fixed backup numbering to match GNU standard better
109
        self.check_file_contents('hello.txt.~1~', 'new hello')
1534.10.28 by Aaron Bentley
Use numbered backup files
110
        
111
        # backup files are numbered
112
        file('hello.txt', 'w').write('new hello2')
113
        tree.revert(['hello.txt'])
114
        self.check_file_contents('hello.txt', 'initial hello')
1534.10.29 by Aaron Bentley
Fixed backup numbering to match GNU standard better
115
        self.check_file_contents('hello.txt.~1~', 'new hello')
116
        self.check_file_contents('hello.txt.~2~', 'new hello2')
1534.4.46 by Robert Collins
Nearly complete .bzr/checkout splitout.
117
1558.12.7 by Aaron Bentley
Fixed revert with missing files
118
    def test_revert_missing(self):
119
        # Revert a file that has been deleted since last commit
120
        tree = self.make_branch_and_tree('.')
121
        file('hello.txt', 'w').write('initial hello')
122
        tree.add('hello.txt')
123
        tree.commit('added hello.txt')
124
        os.unlink('hello.txt')
125
        tree.remove('hello.txt')
126
        tree.revert(['hello.txt'])
127
        self.failUnlessExists('hello.txt')
128
1534.4.46 by Robert Collins
Nearly complete .bzr/checkout splitout.
129
    def test_unknowns(self):
130
        tree = self.make_branch_and_tree('.')
131
        self.build_tree(['hello.txt',
1534.10.29 by Aaron Bentley
Fixed backup numbering to match GNU standard better
132
                         'hello.txt.~1~'])
1534.4.46 by Robert Collins
Nearly complete .bzr/checkout splitout.
133
        self.assertEquals(list(tree.unknowns()),
134
                          ['hello.txt'])
135
136
    def test_hashcache(self):
137
        from bzrlib.tests.test_hashcache import pause
1534.4.50 by Robert Collins
Got the bzrdir api straightened out, plenty of refactoring to use it pending, but the api is up and running.
138
        tree = self.make_branch_and_tree('.')
1534.4.46 by Robert Collins
Nearly complete .bzr/checkout splitout.
139
        self.build_tree(['hello.txt',
1534.10.29 by Aaron Bentley
Fixed backup numbering to match GNU standard better
140
                         'hello.txt.~1~'])
1534.4.46 by Robert Collins
Nearly complete .bzr/checkout splitout.
141
        tree.add('hello.txt')
142
        pause()
143
        sha = tree.get_file_sha1(tree.path2id('hello.txt'))
144
        self.assertEqual(1, tree._hashcache.miss_count)
1534.5.3 by Robert Collins
Make format 4/5/6 branches share a single LockableFiles instance across wt/branch/repository.
145
        tree2 = WorkingTree.open('.')
1534.4.46 by Robert Collins
Nearly complete .bzr/checkout splitout.
146
        sha2 = tree2.get_file_sha1(tree2.path2id('hello.txt'))
147
        self.assertEqual(0, tree2._hashcache.miss_count)
148
        self.assertEqual(1, tree2._hashcache.hit_count)
149
150
    def test_initialize(self):
151
        # initialize should create a working tree and branch in an existing dir
1534.4.50 by Robert Collins
Got the bzrdir api straightened out, plenty of refactoring to use it pending, but the api is up and running.
152
        t = self.make_branch_and_tree('.')
1534.4.46 by Robert Collins
Nearly complete .bzr/checkout splitout.
153
        b = Branch.open('.')
154
        self.assertEqual(t.branch.base, b.base)
1508.1.19 by Robert Collins
Give format3 working trees their own last-revision marker.
155
        t2 = WorkingTree.open('.')
1534.4.46 by Robert Collins
Nearly complete .bzr/checkout splitout.
156
        self.assertEqual(t.basedir, t2.basedir)
157
        self.assertEqual(b.base, t2.branch.base)
158
        # TODO maybe we should check the branch format? not sure if its
159
        # appropriate here.
160
161
    def test_rename_dirs(self):
162
        """Test renaming directories and the files within them."""
163
        wt = self.make_branch_and_tree('.')
164
        b = wt.branch
165
        self.build_tree(['dir/', 'dir/sub/', 'dir/sub/file'])
166
        wt.add(['dir', 'dir/sub', 'dir/sub/file'])
167
168
        wt.commit('create initial state')
169
170
        revid = b.revision_history()[0]
171
        self.log('first revision_id is {%s}' % revid)
172
        
173
        inv = b.repository.get_revision_inventory(revid)
174
        self.log('contents of inventory: %r' % inv.entries())
175
176
        self.check_inventory_shape(inv,
177
                                   ['dir', 'dir/sub', 'dir/sub/file'])
178
179
        wt.rename_one('dir', 'newdir')
180
181
        self.check_inventory_shape(wt.read_working_inventory(),
182
                                   ['newdir', 'newdir/sub', 'newdir/sub/file'])
183
184
        wt.rename_one('newdir/sub', 'newdir/newsub')
185
        self.check_inventory_shape(wt.read_working_inventory(),
186
                                   ['newdir', 'newdir/newsub',
187
                                    'newdir/newsub/file'])
188
189
    def test_add_in_unversioned(self):
190
        """Try to add a file in an unversioned directory.
191
192
        "bzr add" adds the parent as necessary, but simple working tree add
193
        doesn't do that.
194
        """
195
        from bzrlib.errors import NotVersionedError
196
        wt = self.make_branch_and_tree('.')
197
        self.build_tree(['foo/',
198
                         'foo/hello'])
199
        self.assertRaises(NotVersionedError,
200
                          wt.add,
201
                          'foo/hello')
202
203
    def test_add_missing(self):
204
        # adding a msising file -> NoSuchFile
205
        wt = self.make_branch_and_tree('.')
206
        self.assertRaises(errors.NoSuchFile, wt.add, 'fpp')
207
208
    def test_remove_verbose(self):
209
        #FIXME the remove api should not print or otherwise depend on the
210
        # text UI - RBC 20060124
211
        wt = self.make_branch_and_tree('.')
212
        self.build_tree(['hello'])
213
        wt.add(['hello'])
214
        wt.commit(message='add hello')
215
        stdout = StringIO()
216
        stderr = StringIO()
217
        self.assertEqual(None, self.apply_redirected(None, stdout, stderr,
218
                                                     wt.remove,
219
                                                     ['hello'],
220
                                                     verbose=True))
221
        self.assertEqual('?       hello\n', stdout.getvalue())
222
        self.assertEqual('', stderr.getvalue())
223
224
    def test_clone_trivial(self):
225
        wt = self.make_branch_and_tree('source')
1534.4.50 by Robert Collins
Got the bzrdir api straightened out, plenty of refactoring to use it pending, but the api is up and running.
226
        cloned_dir = wt.bzrdir.clone('target')
227
        cloned = cloned_dir.open_workingtree()
1534.4.46 by Robert Collins
Nearly complete .bzr/checkout splitout.
228
        self.assertEqual(cloned.last_revision(), wt.last_revision())
229
230
    def test_last_revision(self):
231
        wt = self.make_branch_and_tree('source')
232
        self.assertEqual(None, wt.last_revision())
233
        wt.commit('A', allow_pointless=True, rev_id='A')
234
        self.assertEqual('A', wt.last_revision())
235
236
    def test_set_last_revision(self):
237
        wt = self.make_branch_and_tree('source')
238
        self.assertEqual(None, wt.last_revision())
1508.1.19 by Robert Collins
Give format3 working trees their own last-revision marker.
239
        # cannot set the last revision to one not in the branch history.
1534.4.46 by Robert Collins
Nearly complete .bzr/checkout splitout.
240
        self.assertRaises(errors.NoSuchRevision, wt.set_last_revision, 'A')
241
        wt.commit('A', allow_pointless=True, rev_id='A')
242
        self.assertEqual('A', wt.last_revision())
243
        # None is aways in the branch
244
        wt.set_last_revision(None)
245
        self.assertEqual(None, wt.last_revision())
246
        # and now we can set it to 'A'
1508.1.19 by Robert Collins
Give format3 working trees their own last-revision marker.
247
        # because some formats mutate the branch to set it on the tree
1534.4.46 by Robert Collins
Nearly complete .bzr/checkout splitout.
248
        # we need to alter the branch to let this pass.
249
        wt.branch.set_revision_history(['A', 'B'])
250
        wt.set_last_revision('A')
251
        self.assertEqual('A', wt.last_revision())
252
1508.1.19 by Robert Collins
Give format3 working trees their own last-revision marker.
253
    def test_set_last_revision_different_to_branch(self):
254
        # working tree formats from the meta-dir format and newer support
255
        # setting the last revision on a tree independently of that on the 
256
        # branch. Its concievable that some future formats may want to 
257
        # couple them again (i.e. because its really a smart server and
258
        # the working tree will always match the branch). So we test
259
        # that formats where initialising a branch does not initialise a 
260
        # tree - and thus have separable entities - support skewing the 
261
        # two things.
262
        branch = self.make_branch('tree')
263
        try:
264
            # if there is a working tree now, this is not supported.
265
            branch.bzrdir.open_workingtree()
266
            return
267
        except errors.NoWorkingTree:
268
            pass
269
        wt = branch.bzrdir.create_workingtree()
270
        wt.commit('A', allow_pointless=True, rev_id='A')
271
        wt.set_last_revision(None)
272
        self.assertEqual(None, wt.last_revision())
273
        self.assertEqual('A', wt.branch.last_revision())
274
        # and now we can set it back to 'A'
275
        wt.set_last_revision('A')
276
        self.assertEqual('A', wt.last_revision())
277
        self.assertEqual('A', wt.branch.last_revision())
278
1534.4.46 by Robert Collins
Nearly complete .bzr/checkout splitout.
279
    def test_clone_and_commit_preserves_last_revision(self):
280
        wt = self.make_branch_and_tree('source')
1534.4.50 by Robert Collins
Got the bzrdir api straightened out, plenty of refactoring to use it pending, but the api is up and running.
281
        cloned_dir = wt.bzrdir.clone('target')
1534.4.46 by Robert Collins
Nearly complete .bzr/checkout splitout.
282
        wt.commit('A', allow_pointless=True, rev_id='A')
1534.4.50 by Robert Collins
Got the bzrdir api straightened out, plenty of refactoring to use it pending, but the api is up and running.
283
        self.assertNotEqual(cloned_dir.open_workingtree().last_revision(),
284
                            wt.last_revision())
285
286
    def test_clone_preserves_content(self):
287
        wt = self.make_branch_and_tree('source')
288
        self.build_tree(['added', 'deleted', 'notadded'], transport=wt.bzrdir.transport.clone('..'))
289
        wt.add('deleted', 'deleted')
290
        wt.commit('add deleted')
291
        wt.remove('deleted')
292
        wt.add('added', 'added')
293
        cloned_dir = wt.bzrdir.clone('target')
294
        cloned = cloned_dir.open_workingtree()
295
        cloned_transport = cloned.bzrdir.transport.clone('..')
296
        self.assertFalse(cloned_transport.has('deleted'))
297
        self.assertTrue(cloned_transport.has('added'))
298
        self.assertFalse(cloned_transport.has('notadded'))
299
        self.assertEqual('added', cloned.path2id('added'))
300
        self.assertEqual(None, cloned.path2id('deleted'))
301
        self.assertEqual(None, cloned.path2id('notadded'))
1534.4.46 by Robert Collins
Nearly complete .bzr/checkout splitout.
302
        
303
    def test_basis_tree_returns_last_revision(self):
304
        wt = self.make_branch_and_tree('.')
305
        self.build_tree(['foo'])
306
        wt.add('foo', 'foo-id')
307
        wt.commit('A', rev_id='A')
308
        wt.rename_one('foo', 'bar')
309
        wt.commit('B', rev_id='B')
310
        wt.set_last_revision('B')
311
        tree = wt.basis_tree()
312
        self.failUnless(tree.has_filename('bar'))
313
        wt.set_last_revision('A')
314
        tree = wt.basis_tree()
315
        self.failUnless(tree.has_filename('foo'))
316
1534.4.50 by Robert Collins
Got the bzrdir api straightened out, plenty of refactoring to use it pending, but the api is up and running.
317
    def test_clone_tree_revision(self):
318
        # make a tree with a last-revision,
319
        # and clone it with a different last-revision, this should switch
320
        # do it.
321
        #
322
        # also test that the content is merged
323
        # and conflicts recorded.
324
        # This should merge between the trees - local edits should be preserved
325
        # but other changes occured.
326
        # we test this by having one file that does
327
        # not change between two revisions, and another that does -
328
        # if the changed one is not changed, fail,
329
        # if the one that did not change has lost a local change, fail.
330
        # 
331
        raise TestSkipped('revision limiting is not implemented yet.')
1508.1.21 by Robert Collins
Implement -r limit for checkout command.
332
333
    def test_initialize_with_revision_id(self):
334
        # a bzrdir can construct a working tree for itself @ a specific revision.
335
        source = self.make_branch_and_tree('source')
336
        source.commit('a', rev_id='a', allow_pointless=True)
337
        source.commit('b', rev_id='b', allow_pointless=True)
338
        self.build_tree(['new/'])
339
        made_control = self.bzrdir_format.initialize('new')
340
        source.branch.repository.clone(made_control)
341
        source.branch.clone(made_control)
342
        made_tree = self.workingtree_format.initialize(made_control, revision_id='a')
343
        self.assertEqual('a', made_tree.last_revision())
1508.1.23 by Robert Collins
Test that the working tree last revision is indeed set during commit.
344
345
    def test_commit_sets_last_revision(self):
346
        tree = self.make_branch_and_tree('tree')
347
        tree.commit('foo', rev_id='foo', allow_pointless=True)
348
        self.assertEqual('foo', tree.last_revision())
1508.1.24 by Robert Collins
Add update command for use with checkouts.
349
1587.1.8 by Robert Collins
Local commits on unbound branches fail.
350
    def test_commit_local_unbound(self):
351
        # using the library api to do a local commit on unbound branches is 
352
        # also an error
353
        tree = self.make_branch_and_tree('tree')
354
        self.assertRaises(errors.LocalRequiresBoundBranch,
355
                          tree.commit,
356
                          'foo',
357
                          local=True)
1587.1.9 by Robert Collins
Local commits do no alter or access the master branch.
358
 
359
    def test_local_commit_ignores_master(self):
360
        # a --local commit does not require access to the master branch
361
        # at all, or even for it to exist.
362
        # we test this by setting up a bound branch and then corrupting
363
        # the master.
364
        master = self.make_branch('master')
365
        tree = self.make_branch_and_tree('tree')
366
        try:
367
            tree.branch.bind(master)
368
        except errors.UpgradeRequired:
369
            # older format.
370
            return
371
        master.bzrdir.transport.put('branch-format', StringIO('garbage'))
372
        del master
373
        # check its corrupted.
374
        self.assertRaises(errors.UnknownFormatError,
375
                          bzrdir.BzrDir.open,
376
                          'master')
377
        tree.commit('foo', rev_id='foo', local=True)
378
 
379
    def test_local_commit_does_not_push_to_master(self):
380
        # a --local commit does not require access to the master branch
381
        # at all, or even for it to exist.
382
        # we test that even when its available it does not push to it.
383
        master = self.make_branch('master')
384
        tree = self.make_branch_and_tree('tree')
385
        try:
386
            tree.branch.bind(master)
387
        except errors.UpgradeRequired:
388
            # older format.
389
            return
390
        tree.commit('foo', rev_id='foo', local=True)
391
        self.failIf(master.repository.has_revision('foo'))
392
        self.assertEqual(None, master.last_revision())
393
        
1508.1.24 by Robert Collins
Add update command for use with checkouts.
394
    def test_update_sets_last_revision(self):
395
        # working tree formats from the meta-dir format and newer support
396
        # setting the last revision on a tree independently of that on the 
397
        # branch. Its concievable that some future formats may want to 
398
        # couple them again (i.e. because its really a smart server and
399
        # the working tree will always match the branch). So we test
400
        # that formats where initialising a branch does not initialise a 
401
        # tree - and thus have separable entities - support skewing the 
402
        # two things.
403
        main_branch = self.make_branch('tree')
404
        try:
405
            # if there is a working tree now, this is not supported.
406
            main_branch.bzrdir.open_workingtree()
407
            return
408
        except errors.NoWorkingTree:
409
            pass
410
        wt = main_branch.bzrdir.create_workingtree()
411
        # create an out of date working tree by making a checkout in this
412
        # current format
413
        self.build_tree(['checkout/', 'tree/file'])
414
        checkout = bzrdir.BzrDirMetaFormat1().initialize('checkout')
1508.1.25 by Robert Collins
Update per review comments.
415
        bzrlib.branch.BranchReferenceFormat().initialize(checkout, main_branch)
1508.1.24 by Robert Collins
Add update command for use with checkouts.
416
        old_tree = self.workingtree_format.initialize(checkout)
417
        # now commit to 'tree'
418
        wt.add('file')
419
        wt.commit('A', rev_id='A')
420
        # and update old_tree
421
        self.assertEqual(0, old_tree.update())
422
        self.failUnlessExists('checkout/file')
423
        self.assertEqual('A', old_tree.last_revision())
424
425
    def test_update_returns_conflict_count(self):
426
        # working tree formats from the meta-dir format and newer support
427
        # setting the last revision on a tree independently of that on the 
428
        # branch. Its concievable that some future formats may want to 
429
        # couple them again (i.e. because its really a smart server and
430
        # the working tree will always match the branch). So we test
431
        # that formats where initialising a branch does not initialise a 
432
        # tree - and thus have separable entities - support skewing the 
433
        # two things.
434
        main_branch = self.make_branch('tree')
435
        try:
436
            # if there is a working tree now, this is not supported.
437
            main_branch.bzrdir.open_workingtree()
438
            return
439
        except errors.NoWorkingTree:
440
            pass
441
        wt = main_branch.bzrdir.create_workingtree()
442
        # create an out of date working tree by making a checkout in this
443
        # current format
444
        self.build_tree(['checkout/', 'tree/file'])
445
        checkout = bzrdir.BzrDirMetaFormat1().initialize('checkout')
1508.1.25 by Robert Collins
Update per review comments.
446
        bzrlib.branch.BranchReferenceFormat().initialize(checkout, main_branch)
1508.1.24 by Robert Collins
Add update command for use with checkouts.
447
        old_tree = self.workingtree_format.initialize(checkout)
448
        # now commit to 'tree'
449
        wt.add('file')
450
        wt.commit('A', rev_id='A')
451
        # and add a file file to the checkout
452
        self.build_tree(['checkout/file'])
453
        old_tree.add('file')
454
        # and update old_tree
455
        self.assertEqual(1, old_tree.update())
456
        self.assertEqual('A', old_tree.last_revision())
457
1534.7.199 by Aaron Bentley
Moved merge/revert tests into test_workingtree.py
458
    def test_merge_revert(self):
459
        from bzrlib.merge import merge_inner
460
        this = self.make_branch_and_tree('b1')
461
        open('b1/a', 'wb').write('a test\n')
462
        this.add('a')
463
        open('b1/b', 'wb').write('b test\n')
464
        this.add('b')
465
        this.commit(message='')
466
        base = this.bzrdir.clone('b2').open_workingtree()
467
        open('b2/a', 'wb').write('b test\n')
468
        other = this.bzrdir.clone('b3').open_workingtree()
469
        open('b3/a', 'wb').write('c test\n')
470
        open('b3/c', 'wb').write('c test\n')
471
        other.add('c')
472
473
        open('b1/b', 'wb').write('q test\n')
474
        open('b1/d', 'wb').write('d test\n')
475
        merge_inner(this.branch, other, base, this_tree=this)
476
        self.assertNotEqual(open('b1/a', 'rb').read(), 'a test\n')
477
        this.revert([])
478
        self.assertEqual(open('b1/a', 'rb').read(), 'a test\n')
1534.10.29 by Aaron Bentley
Fixed backup numbering to match GNU standard better
479
        self.assertIs(os.path.exists('b1/b.~1~'), True)
1534.7.199 by Aaron Bentley
Moved merge/revert tests into test_workingtree.py
480
        self.assertIs(os.path.exists('b1/c'), False)
1534.10.29 by Aaron Bentley
Fixed backup numbering to match GNU standard better
481
        self.assertIs(os.path.exists('b1/a.~1~'), False)
1534.7.199 by Aaron Bentley
Moved merge/revert tests into test_workingtree.py
482
        self.assertIs(os.path.exists('b1/d'), True)
1534.7.200 by Aaron Bentley
Merge from mainline
483
1587.1.10 by Robert Collins
update updates working tree and branch together.
484
    def test_update_updates_bound_branch_no_local_commits(self):
485
        # doing an update in a tree updates the branch its bound to too.
486
        master_tree = self.make_branch_and_tree('master')
487
        tree = self.make_branch_and_tree('tree')
488
        try:
489
            tree.branch.bind(master_tree.branch)
490
        except errors.UpgradeRequired:
491
            # legacy branches cannot bind
492
            return
493
        master_tree.commit('foo', rev_id='foo', allow_pointless=True)
494
        tree.update()
495
        self.assertEqual('foo', tree.last_revision())
496
        self.assertEqual('foo', tree.branch.last_revision())
1587.1.11 by Robert Collins
Local commits appear to be working properly.
497
498
    def test_update_turns_local_commit_into_merge(self):
499
        # doing an update with a few local commits and no master commits
1587.1.13 by Robert Collins
Explain why update pivots more clearly in the relevant test.
500
        # makes pending-merges. 
501
        # this is done so that 'bzr update; bzr revert' will always produce
502
        # an exact copy of the 'logical branch' - the referenced branch for
503
        # a checkout, and the master for a bound branch.
504
        # its possible that we should instead have 'bzr update' when there
505
        # is nothing new on the master leave the current commits intact and
506
        # alter 'revert' to revert to the master always. But for now, its
507
        # good.
1587.1.11 by Robert Collins
Local commits appear to be working properly.
508
        master_tree = self.make_branch_and_tree('master')
509
        tree = self.make_branch_and_tree('tree')
510
        try:
511
            tree.branch.bind(master_tree.branch)
512
        except errors.UpgradeRequired:
513
            # legacy branches cannot bind
514
            return
515
        tree.commit('foo', rev_id='foo', allow_pointless=True, local=True)
516
        tree.commit('bar', rev_id='bar', allow_pointless=True, local=True)
517
        tree.update()
518
        self.assertEqual(None, tree.last_revision())
519
        self.assertEqual([], tree.branch.revision_history())
520
        self.assertEqual(['bar'], tree.pending_merges())
521
1558.3.3 by Aaron Bentley
Fix error handling for merge_modified
522
    def test_merge_modified(self):
523
        tree = self.make_branch_and_tree('master')
524
        tree._control_files.put('merge-hashes', StringIO('asdfasdf'))
525
        self.assertRaises(errors.MergeModifiedFormatError, tree.merge_modified)
1534.10.8 by Aaron Bentley
Implemented conflict_lines in terms of old system on WorkingTree
526
1534.10.22 by Aaron Bentley
Got ConflictList implemented
527
    def test_conflicts(self):
1534.10.8 by Aaron Bentley
Implemented conflict_lines in terms of old system on WorkingTree
528
        from bzrlib.tests.test_conflicts import example_conflicts
529
        tree = self.make_branch_and_tree('master')
530
        try:
1534.10.22 by Aaron Bentley
Got ConflictList implemented
531
            tree.set_conflicts(example_conflicts)
1534.10.8 by Aaron Bentley
Implemented conflict_lines in terms of old system on WorkingTree
532
        except UnsupportedOperation:
1534.10.22 by Aaron Bentley
Got ConflictList implemented
533
            raise TestSkipped('set_conflicts not supported')
1534.10.8 by Aaron Bentley
Implemented conflict_lines in terms of old system on WorkingTree
534
            
535
        tree2 = WorkingTree.open('master')
1534.10.22 by Aaron Bentley
Got ConflictList implemented
536
        self.assertEqual(tree2.conflicts(), example_conflicts)
1534.10.8 by Aaron Bentley
Implemented conflict_lines in terms of old system on WorkingTree
537
        tree2._control_files.put('conflicts', StringIO(''))
538
        self.assertRaises(errors.ConflictFormatError, 
1534.10.22 by Aaron Bentley
Got ConflictList implemented
539
                          tree2.conflicts)
1534.10.8 by Aaron Bentley
Implemented conflict_lines in terms of old system on WorkingTree
540
        tree2._control_files.put('conflicts', StringIO('a'))
541
        self.assertRaises(errors.ConflictFormatError, 
1534.10.22 by Aaron Bentley
Got ConflictList implemented
542
                          tree2.conflicts)
1534.10.12 by Aaron Bentley
Merge produces new conflicts
543
544
    def make_merge_conflicts(self):
545
        from bzrlib.merge import merge_inner 
546
        tree = self.make_branch_and_tree('mine')
547
        file('mine/bloo', 'wb').write('one')
548
        tree.add('bloo')
1534.10.14 by Aaron Bentley
Made revert clear conflicts
549
        file('mine/blo', 'wb').write('on')
550
        tree.add('blo')
1534.10.12 by Aaron Bentley
Merge produces new conflicts
551
        tree.commit("blah", allow_pointless=False)
552
        base = tree.basis_tree()
553
        BzrDir.open("mine").sprout("other")
554
        file('other/bloo', 'wb').write('two')
555
        othertree = WorkingTree.open('other')
556
        othertree.commit('blah', allow_pointless=False)
557
        file('mine/bloo', 'wb').write('three')
558
        tree.commit("blah", allow_pointless=False)
559
        merge_inner(tree.branch, othertree, base, this_tree=tree)
560
        return tree
561
562
    def test_merge_conflicts(self):
563
        tree = self.make_merge_conflicts()
1534.10.22 by Aaron Bentley
Got ConflictList implemented
564
        self.assertEqual(len(tree.conflicts()), 1)
1534.10.12 by Aaron Bentley
Merge produces new conflicts
565
566
    def test_clear_merge_conflicts(self):
1534.10.22 by Aaron Bentley
Got ConflictList implemented
567
        from bzrlib.conflicts import ConflictList
1534.10.12 by Aaron Bentley
Merge produces new conflicts
568
        tree = self.make_merge_conflicts()
1534.10.22 by Aaron Bentley
Got ConflictList implemented
569
        self.assertEqual(len(tree.conflicts()), 1)
1534.10.12 by Aaron Bentley
Merge produces new conflicts
570
        try:
1534.10.22 by Aaron Bentley
Got ConflictList implemented
571
            tree.set_conflicts(ConflictList())
1534.10.12 by Aaron Bentley
Merge produces new conflicts
572
        except UnsupportedOperation:
573
            raise TestSkipped
1534.10.22 by Aaron Bentley
Got ConflictList implemented
574
        self.assertEqual(tree.conflicts(), ConflictList())
1534.10.14 by Aaron Bentley
Made revert clear conflicts
575
576
    def test_revert_clear_conflicts(self):
577
        tree = self.make_merge_conflicts()
1534.10.22 by Aaron Bentley
Got ConflictList implemented
578
        self.assertEqual(len(tree.conflicts()), 1)
1534.10.14 by Aaron Bentley
Made revert clear conflicts
579
        tree.revert(["blo"])
1534.10.22 by Aaron Bentley
Got ConflictList implemented
580
        self.assertEqual(len(tree.conflicts()), 1)
1534.10.14 by Aaron Bentley
Made revert clear conflicts
581
        tree.revert(["bloo"])
1534.10.22 by Aaron Bentley
Got ConflictList implemented
582
        self.assertEqual(len(tree.conflicts()), 0)
1534.10.14 by Aaron Bentley
Made revert clear conflicts
583
584
    def test_revert_clear_conflicts2(self):
585
        tree = self.make_merge_conflicts()
1534.10.22 by Aaron Bentley
Got ConflictList implemented
586
        self.assertEqual(len(tree.conflicts()), 1)
1534.10.14 by Aaron Bentley
Made revert clear conflicts
587
        tree.revert([])
1534.10.22 by Aaron Bentley
Got ConflictList implemented
588
        self.assertEqual(len(tree.conflicts()), 0)
1624.3.22 by Olaf Conradi
Merge bzr.dev
589
1624.3.19 by Olaf Conradi
New call get_format_description to give a user-friendly description of a
590
    def test_format_description(self):
591
        tree = self.make_branch_and_tree('tree')
592
        text = tree._format.get_format_description()
593
        self.failUnless(len(text))
1681.1.1 by Robert Collins
Make WorkingTree.branch a read only property. (Robert Collins)
594
595
    def test_branch_attribute_is_not_settable(self):
596
        # the branch attribute is an aspect of the working tree, not a
597
        # configurable attribute
598
        tree = self.make_branch_and_tree('tree')
599
        def set_branch():
600
            tree.branch = tree.branch
601
        self.assertRaises(AttributeError, set_branch)
602