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
from bzrlib.errors import NotBranchError, NotVersionedError
24
from bzrlib.tests import TestCaseWithTransport
25
from bzrlib.trace import mutter
26
from bzrlib.osutils import pathjoin, getcwd, has_symlinks
27
from bzrlib.workingtree import (TreeEntry, TreeDirectory, TreeFile, TreeLink,
30
class TestTreeDirectory(TestCaseWithTransport):
32
def test_kind_character(self):
33
self.assertEqual(TreeDirectory().kind_character(), '/')
36
class TestTreeEntry(TestCaseWithTransport):
38
def test_kind_character(self):
39
self.assertEqual(TreeEntry().kind_character(), '???')
42
class TestTreeFile(TestCaseWithTransport):
44
def test_kind_character(self):
45
self.assertEqual(TreeFile().kind_character(), '')
48
class TestTreeLink(TestCaseWithTransport):
50
def test_kind_character(self):
51
self.assertEqual(TreeLink().kind_character(), '')
54
class TestWorkingTree(TestCaseWithTransport):
56
def test_listfiles(self):
57
tree = WorkingTree.create_standalone('.')
59
print >> open('file', 'w'), "content"
61
os.symlink('target', 'symlink')
62
files = list(tree.list_files())
63
self.assertEqual(files[0], ('dir', '?', 'directory', None, TreeDirectory()))
64
self.assertEqual(files[1], ('file', '?', 'file', None, TreeFile()))
66
self.assertEqual(files[2], ('symlink', '?', 'symlink', None, TreeLink()))
68
def test_open_containing(self):
69
branch = WorkingTree.create_standalone('.').branch
70
wt, relpath = WorkingTree.open_containing()
71
self.assertEqual('', relpath)
72
self.assertEqual(wt.basedir + '/', branch.base)
73
wt, relpath = WorkingTree.open_containing(u'.')
74
self.assertEqual('', relpath)
75
self.assertEqual(wt.basedir + '/', branch.base)
76
wt, relpath = WorkingTree.open_containing('./foo')
77
self.assertEqual('foo', relpath)
78
self.assertEqual(wt.basedir + '/', branch.base)
79
# paths that are urls are just plain wrong for working trees.
80
self.assertRaises(NotBranchError,
81
WorkingTree.open_containing,
82
'file:///' + getcwd())
84
def test_construct_with_branch(self):
85
branch = WorkingTree.create_standalone('.').branch
86
tree = WorkingTree(branch.base, branch)
87
self.assertEqual(branch, tree.branch)
88
self.assertEqual(branch.base, tree.basedir + '/')
90
def test_construct_without_branch(self):
91
branch = WorkingTree.create_standalone('.').branch
92
tree = WorkingTree(branch.base)
93
self.assertEqual(branch.base, tree.branch.base)
94
self.assertEqual(branch.base, tree.basedir + '/')
96
def test_basic_relpath(self):
97
# for comprehensive relpath tests, see whitebox.py.
98
tree = WorkingTree.create_standalone('.')
99
self.assertEqual('child',
100
tree.relpath(pathjoin(getcwd(), 'child')))
102
def test_lock_locks_branch(self):
103
tree = WorkingTree.create_standalone('.')
105
self.assertEqual(1, tree.branch._lock_count)
106
self.assertEqual('r', tree.branch._lock_mode)
108
self.assertEqual(None, tree.branch._lock_count)
110
self.assertEqual(1, tree.branch._lock_count)
111
self.assertEqual('w', tree.branch._lock_mode)
113
self.assertEqual(None, tree.branch._lock_count)
115
def get_pullable_trees(self):
116
self.build_tree(['from/', 'from/file', 'to/'])
117
tree = WorkingTree.create_standalone('from')
119
tree.commit('foo', rev_id='A')
120
tree_b = WorkingTree.create_standalone('to')
124
tree_a, tree_b = self.get_pullable_trees()
125
tree_b.pull(tree_a.branch)
126
self.failUnless(tree_b.branch.has_revision('A'))
127
self.assertEqual(['A'], tree_b.branch.revision_history())
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.has_revision('A'))
135
self.failUnless(tree_b.branch.has_revision('B'))
136
self.assertEqual(['A'], tree_b.branch.revision_history())
138
def test_revert(self):
139
"""Test selected-file revert"""
140
tree = WorkingTree.create_standalone('.')
142
self.build_tree(['hello.txt'])
143
file('hello.txt', 'w').write('initial hello')
145
self.assertRaises(NotVersionedError,
146
tree.revert, ['hello.txt'])
147
tree.add(['hello.txt'])
148
tree.commit('create initial hello.txt')
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')
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')
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')
164
def test_unknowns(self):
165
tree = WorkingTree.create_standalone('.')
166
self.build_tree(['hello.txt',
168
self.assertEquals(list(tree.unknowns()),
171
def test_hashcache(self):
172
from bzrlib.tests.test_hashcache import pause
173
tree = WorkingTree.create_standalone('.')
174
self.build_tree(['hello.txt',
176
tree.add('hello.txt')
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)
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
self.build_tree(['branch/'])
189
b = Branch.create('branch')
190
t = WorkingTree.create(b, 'tree')
191
# as we are moving the ownership to working tree, we will check here
192
# that its split out correctly
193
self.failIfExists('branch/.bzr/inventory')
194
self.failIfExists('branch/.bzr/pending-merges')
196
bzrlib.xml5.serializer_v5.write_inventory(bzrlib.inventory.Inventory(),
198
self.assertFileEqual(sio.getvalue(), 'tree/.bzr/inventory')
199
self.assertFileEqual('', 'tree/.bzr/pending-merges')
201
def test_initialize(self):
202
# initialize should create a working tree and branch in an existing dir
203
t = WorkingTree.create_standalone('.')
205
self.assertEqual(t.branch.base, b.base)
206
t2 = WorkingTree('.')
207
self.assertEqual(t.basedir, t2.basedir)
208
self.assertEqual(b.base, t2.branch.base)
209
# TODO maybe we should check the branch format? not sure if its
212
def test_rename_dirs(self):
213
"""Test renaming directories and the files within them."""
214
wt = self.make_branch_and_tree('.')
216
self.build_tree(['dir/', 'dir/sub/', 'dir/sub/file'])
217
wt.add(['dir', 'dir/sub', 'dir/sub/file'])
219
wt.commit('create initial state')
221
revid = b.revision_history()[0]
222
self.log('first revision_id is {%s}' % revid)
224
inv = b.get_revision_inventory(revid)
225
self.log('contents of inventory: %r' % inv.entries())
227
self.check_inventory_shape(inv,
228
['dir', 'dir/sub', 'dir/sub/file'])
230
wt.rename_one('dir', 'newdir')
232
self.check_inventory_shape(wt.read_working_inventory(),
233
['newdir', 'newdir/sub', 'newdir/sub/file'])
235
wt.rename_one('newdir/sub', 'newdir/newsub')
236
self.check_inventory_shape(wt.read_working_inventory(),
237
['newdir', 'newdir/newsub',
238
'newdir/newsub/file'])
240
def test_add_in_unversioned(self):
241
"""Try to add a file in an unversioned directory.
243
"bzr add" adds the parent as necessary, but simple working tree add
246
from bzrlib.errors import NotVersionedError
247
wt = self.make_branch_and_tree('.')
248
self.build_tree(['foo/',
250
self.assertRaises(NotVersionedError,
254
def test_remove_verbose(self):
255
#FIXME the remove api should not print or otherwise depend on the
256
# text UI - RBC 20060124
257
wt = self.make_branch_and_tree('.')
258
self.build_tree(['hello'])
260
wt.commit(message='add hello')
263
self.assertEqual(None, self.apply_redirected(None, stdout, stderr,
267
self.assertEqual('? hello\n', stdout.getvalue())
268
self.assertEqual('', stderr.getvalue())