1
# (C) 2005 Canonical Ltd
2
# Authors: Robert Collins <robert.collins@canonical.com>
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.
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.
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
18
from cStringIO import StringIO
22
from bzrlib.branch import Branch
23
import bzrlib.errors as errors
24
from bzrlib.errors import NotBranchError, NotVersionedError
25
from bzrlib.tests import TestCaseWithTransport
26
from bzrlib.trace import mutter
27
from bzrlib.osutils import pathjoin, getcwd, has_symlinks
28
from bzrlib.workingtree import (TreeEntry, TreeDirectory, TreeFile, TreeLink,
31
class TestTreeDirectory(TestCaseWithTransport):
33
def test_kind_character(self):
34
self.assertEqual(TreeDirectory().kind_character(), '/')
37
class TestTreeEntry(TestCaseWithTransport):
39
def test_kind_character(self):
40
self.assertEqual(TreeEntry().kind_character(), '???')
43
class TestTreeFile(TestCaseWithTransport):
45
def test_kind_character(self):
46
self.assertEqual(TreeFile().kind_character(), '')
49
class TestTreeLink(TestCaseWithTransport):
51
def test_kind_character(self):
52
self.assertEqual(TreeLink().kind_character(), '')
55
class TestWorkingTree(TestCaseWithTransport):
57
def test_listfiles(self):
58
tree = WorkingTree.create_standalone('.')
60
print >> open('file', 'w'), "content"
62
os.symlink('target', 'symlink')
63
files = list(tree.list_files())
64
self.assertEqual(files[0], ('dir', '?', 'directory', None, TreeDirectory()))
65
self.assertEqual(files[1], ('file', '?', 'file', None, TreeFile()))
67
self.assertEqual(files[2], ('symlink', '?', 'symlink', None, TreeLink()))
69
def test_open_containing(self):
70
branch = WorkingTree.create_standalone('.').branch
71
wt, relpath = WorkingTree.open_containing()
72
self.assertEqual('', relpath)
73
self.assertEqual(wt.basedir + '/', branch.base)
74
wt, relpath = WorkingTree.open_containing(u'.')
75
self.assertEqual('', relpath)
76
self.assertEqual(wt.basedir + '/', branch.base)
77
wt, relpath = WorkingTree.open_containing('./foo')
78
self.assertEqual('foo', relpath)
79
self.assertEqual(wt.basedir + '/', branch.base)
80
# paths that are urls are just plain wrong for working trees.
81
self.assertRaises(NotBranchError,
82
WorkingTree.open_containing,
83
'file:///' + getcwd())
85
def test_construct_with_branch(self):
86
branch = WorkingTree.create_standalone('.').branch
87
tree = WorkingTree(branch.base, branch)
88
self.assertEqual(branch, tree.branch)
89
self.assertEqual(branch.base, tree.basedir + '/')
91
def test_construct_without_branch(self):
92
branch = WorkingTree.create_standalone('.').branch
93
tree = WorkingTree(branch.base)
94
self.assertEqual(branch.base, tree.branch.base)
95
self.assertEqual(branch.base, tree.basedir + '/')
97
def test_basic_relpath(self):
98
# for comprehensive relpath tests, see whitebox.py.
99
tree = WorkingTree.create_standalone('.')
100
self.assertEqual('child',
101
tree.relpath(pathjoin(getcwd(), 'child')))
103
def test_lock_locks_branch(self):
104
tree = WorkingTree.create_standalone('.')
106
self.assertEqual('r', tree.branch.peek_lock_mode())
108
self.assertEqual(None, tree.branch.peek_lock_mode())
110
self.assertEqual('w', tree.branch.peek_lock_mode())
112
self.assertEqual(None, tree.branch.peek_lock_mode())
114
def get_pullable_trees(self):
115
self.build_tree(['from/', 'from/file', 'to/'])
116
tree = WorkingTree.create_standalone('from')
118
tree.commit('foo', rev_id='A')
119
tree_b = WorkingTree.create_standalone('to')
123
tree_a, tree_b = self.get_pullable_trees()
124
tree_b.pull(tree_a.branch)
125
self.failUnless(tree_b.branch.repository.has_revision('A'))
126
self.assertEqual(['A'], tree_b.branch.revision_history())
128
def test_pull_overwrites(self):
129
tree_a, tree_b = self.get_pullable_trees()
130
tree_b.commit('foo', rev_id='B')
131
self.assertEqual(['B'], tree_b.branch.revision_history())
132
tree_b.pull(tree_a.branch, overwrite=True)
133
self.failUnless(tree_b.branch.repository.has_revision('A'))
134
self.failUnless(tree_b.branch.repository.has_revision('B'))
135
self.assertEqual(['A'], tree_b.branch.revision_history())
137
def test_revert(self):
138
"""Test selected-file revert"""
139
tree = WorkingTree.create_standalone('.')
141
self.build_tree(['hello.txt'])
142
file('hello.txt', 'w').write('initial hello')
144
self.assertRaises(NotVersionedError,
145
tree.revert, ['hello.txt'])
146
tree.add(['hello.txt'])
147
tree.commit('create initial hello.txt')
149
self.check_file_contents('hello.txt', 'initial hello')
150
file('hello.txt', 'w').write('new hello')
151
self.check_file_contents('hello.txt', 'new hello')
153
# revert file modified since last revision
154
tree.revert(['hello.txt'])
155
self.check_file_contents('hello.txt', 'initial hello')
156
self.check_file_contents('hello.txt~', 'new hello')
158
# reverting again does not clobber the backup
159
tree.revert(['hello.txt'])
160
self.check_file_contents('hello.txt', 'initial hello')
161
self.check_file_contents('hello.txt~', 'new hello')
163
def test_unknowns(self):
164
tree = WorkingTree.create_standalone('.')
165
self.build_tree(['hello.txt',
167
self.assertEquals(list(tree.unknowns()),
170
def test_hashcache(self):
171
from bzrlib.tests.test_hashcache import pause
172
tree = WorkingTree.create_standalone('.')
173
self.build_tree(['hello.txt',
175
tree.add('hello.txt')
177
sha = tree.get_file_sha1(tree.path2id('hello.txt'))
178
self.assertEqual(1, tree._hashcache.miss_count)
179
tree2 = WorkingTree('.', tree.branch)
180
sha2 = tree2.get_file_sha1(tree2.path2id('hello.txt'))
181
self.assertEqual(0, tree2._hashcache.miss_count)
182
self.assertEqual(1, tree2._hashcache.hit_count)
184
def test_checkout(self):
185
# at this point as we dont have checkout versions, checkout simply
186
# populates the required files for a working tree at the dir.
187
self.build_tree(['branch/'])
188
b = Branch.create('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')
195
bzrlib.xml5.serializer_v5.write_inventory(bzrlib.inventory.Inventory(),
197
self.assertFileEqual(sio.getvalue(), 'tree/.bzr/inventory')
198
self.assertFileEqual('', 'tree/.bzr/pending-merges')
200
def test_initialize(self):
201
# initialize should create a working tree and branch in an existing dir
202
t = WorkingTree.create_standalone('.')
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
211
def test_rename_dirs(self):
212
"""Test renaming directories and the files within them."""
213
wt = self.make_branch_and_tree('.')
215
self.build_tree(['dir/', 'dir/sub/', 'dir/sub/file'])
216
wt.add(['dir', 'dir/sub', 'dir/sub/file'])
218
wt.commit('create initial state')
220
revid = b.revision_history()[0]
221
self.log('first revision_id is {%s}' % revid)
223
inv = b.repository.get_revision_inventory(revid)
224
self.log('contents of inventory: %r' % inv.entries())
226
self.check_inventory_shape(inv,
227
['dir', 'dir/sub', 'dir/sub/file'])
229
wt.rename_one('dir', 'newdir')
231
self.check_inventory_shape(wt.read_working_inventory(),
232
['newdir', 'newdir/sub', 'newdir/sub/file'])
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'])
239
def test_add_in_unversioned(self):
240
"""Try to add a file in an unversioned directory.
242
"bzr add" adds the parent as necessary, but simple working tree add
245
from bzrlib.errors import NotVersionedError
246
wt = self.make_branch_and_tree('.')
247
self.build_tree(['foo/',
249
self.assertRaises(NotVersionedError,
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')
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'])
264
wt.commit(message='add hello')
267
self.assertEqual(None, self.apply_redirected(None, stdout, stderr,
271
self.assertEqual('? hello\n', stdout.getvalue())
272
self.assertEqual('', stderr.getvalue())
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())
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())
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())
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())
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'))