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('r', tree.branch.peek_lock_mode())
107
self.assertEqual(None, tree.branch.peek_lock_mode())
109
self.assertEqual('w', tree.branch.peek_lock_mode())
111
self.assertEqual(None, tree.branch.peek_lock_mode())
113
def get_pullable_trees(self):
114
self.build_tree(['from/', 'from/file', 'to/'])
115
tree = WorkingTree.create_standalone('from')
117
tree.commit('foo', rev_id='A')
118
tree_b = WorkingTree.create_standalone('to')
122
tree_a, tree_b = self.get_pullable_trees()
123
tree_b.pull(tree_a.branch)
124
self.failUnless(tree_b.branch.repository.has_revision('A'))
125
self.assertEqual(['A'], tree_b.branch.revision_history())
127
def test_pull_overwrites(self):
128
tree_a, tree_b = self.get_pullable_trees()
129
tree_b.commit('foo', rev_id='B')
130
self.assertEqual(['B'], tree_b.branch.revision_history())
131
tree_b.pull(tree_a.branch, overwrite=True)
132
self.failUnless(tree_b.branch.repository.has_revision('A'))
133
self.failUnless(tree_b.branch.repository.has_revision('B'))
134
self.assertEqual(['A'], tree_b.branch.revision_history())
136
def test_revert(self):
137
"""Test selected-file revert"""
138
tree = WorkingTree.create_standalone('.')
140
self.build_tree(['hello.txt'])
141
file('hello.txt', 'w').write('initial hello')
143
self.assertRaises(NotVersionedError,
144
tree.revert, ['hello.txt'])
145
tree.add(['hello.txt'])
146
tree.commit('create initial hello.txt')
148
self.check_file_contents('hello.txt', 'initial hello')
149
file('hello.txt', 'w').write('new hello')
150
self.check_file_contents('hello.txt', 'new hello')
152
# revert file modified since last revision
153
tree.revert(['hello.txt'])
154
self.check_file_contents('hello.txt', 'initial hello')
155
self.check_file_contents('hello.txt~', 'new hello')
157
# reverting again does not clobber the backup
158
tree.revert(['hello.txt'])
159
self.check_file_contents('hello.txt', 'initial hello')
160
self.check_file_contents('hello.txt~', 'new hello')
162
def test_unknowns(self):
163
tree = WorkingTree.create_standalone('.')
164
self.build_tree(['hello.txt',
166
self.assertEquals(list(tree.unknowns()),
169
def test_hashcache(self):
170
from bzrlib.tests.test_hashcache import pause
171
tree = WorkingTree.create_standalone('.')
172
self.build_tree(['hello.txt',
174
tree.add('hello.txt')
176
sha = tree.get_file_sha1(tree.path2id('hello.txt'))
177
self.assertEqual(1, tree._hashcache.miss_count)
178
tree2 = WorkingTree('.', tree.branch)
179
sha2 = tree2.get_file_sha1(tree2.path2id('hello.txt'))
180
self.assertEqual(0, tree2._hashcache.miss_count)
181
self.assertEqual(1, tree2._hashcache.hit_count)
183
def test_checkout(self):
184
# at this point as we dont have checkout versions, checkout simply
185
# populates the required files for a working tree at the dir.
186
self.build_tree(['branch/'])
187
b = Branch.create('branch')
188
t = WorkingTree.create(b, 'tree')
189
# as we are moving the ownership to working tree, we will check here
190
# that its split out correctly
191
self.failIfExists('branch/.bzr/inventory')
192
self.failIfExists('branch/.bzr/pending-merges')
194
bzrlib.xml5.serializer_v5.write_inventory(bzrlib.inventory.Inventory(),
196
self.assertFileEqual(sio.getvalue(), 'tree/.bzr/inventory')
197
self.assertFileEqual('', 'tree/.bzr/pending-merges')
199
def test_initialize(self):
200
# initialize should create a working tree and branch in an existing dir
201
t = WorkingTree.create_standalone('.')
203
self.assertEqual(t.branch.base, b.base)
204
t2 = WorkingTree('.')
205
self.assertEqual(t.basedir, t2.basedir)
206
self.assertEqual(b.base, t2.branch.base)
207
# TODO maybe we should check the branch format? not sure if its
210
def test_rename_dirs(self):
211
"""Test renaming directories and the files within them."""
212
wt = self.make_branch_and_tree('.')
214
self.build_tree(['dir/', 'dir/sub/', 'dir/sub/file'])
215
wt.add(['dir', 'dir/sub', 'dir/sub/file'])
217
wt.commit('create initial state')
219
revid = b.revision_history()[0]
220
self.log('first revision_id is {%s}' % revid)
222
inv = b.repository.get_revision_inventory(revid)
223
self.log('contents of inventory: %r' % inv.entries())
225
self.check_inventory_shape(inv,
226
['dir', 'dir/sub', 'dir/sub/file'])
228
wt.rename_one('dir', 'newdir')
230
self.check_inventory_shape(wt.read_working_inventory(),
231
['newdir', 'newdir/sub', 'newdir/sub/file'])
233
wt.rename_one('newdir/sub', 'newdir/newsub')
234
self.check_inventory_shape(wt.read_working_inventory(),
235
['newdir', 'newdir/newsub',
236
'newdir/newsub/file'])
238
def test_add_in_unversioned(self):
239
"""Try to add a file in an unversioned directory.
241
"bzr add" adds the parent as necessary, but simple working tree add
244
from bzrlib.errors import NotVersionedError
245
wt = self.make_branch_and_tree('.')
246
self.build_tree(['foo/',
248
self.assertRaises(NotVersionedError,
252
def test_remove_verbose(self):
253
#FIXME the remove api should not print or otherwise depend on the
254
# text UI - RBC 20060124
255
wt = self.make_branch_and_tree('.')
256
self.build_tree(['hello'])
258
wt.commit(message='add hello')
261
self.assertEqual(None, self.apply_redirected(None, stdout, stderr,
265
self.assertEqual('? hello\n', stdout.getvalue())
266
self.assertEqual('', stderr.getvalue())