1
# Copyright (C) 2006, 2007 Canonical Ltd
3
# This program is free software; you can redistribute it and/or modify
4
# it under the terms of the GNU General Public License as published by
5
# the Free Software Foundation; either version 2 of the License, or
6
# (at your option) any later version.
8
# This program is distributed in the hope that it will be useful,
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11
# GNU General Public License for more details.
13
# You should have received a copy of the GNU General Public License
14
# along with this program; if not, write to the Free Software
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17
"""Tests for interface conformance of 'WorkingTree.move'"""
26
from bzrlib.workingtree_4 import WorkingTreeFormat4
27
from bzrlib.tests.workingtree_implementations import TestCaseWithWorkingTree
30
class TestMove(TestCaseWithWorkingTree):
32
def get_tree_layout(self, tree):
33
"""Get the (path, file_id) pairs for the current tree."""
36
return [(path, ie.file_id) for path, ie
37
in tree.iter_entries_by_dir()]
41
def assertTreeLayout(self, expected, tree):
42
"""Check that the tree has the correct layout."""
43
actual = self.get_tree_layout(tree)
44
self.assertEqual(expected, actual)
46
def test_move_correct_call_named(self):
47
"""tree.move has the deprecated parameter 'to_name'.
48
It has been replaced by 'to_dir' for consistency.
49
Test the new API using named parameter
51
self.build_tree(['a1', 'sub1/'])
52
tree = self.make_branch_and_tree('.')
53
tree.add(['a1', 'sub1'])
54
tree.commit('initial commit')
55
self.assertEqual([('a1', 'sub1/a1')],
56
tree.move(['a1'], to_dir='sub1', after=False))
58
def test_move_correct_call_unnamed(self):
59
"""tree.move has the deprecated parameter 'to_name'.
60
It has been replaced by 'to_dir' for consistency.
61
Test the new API using unnamed parameter
63
self.build_tree(['a1', 'sub1/'])
64
tree = self.make_branch_and_tree('.')
65
tree.add(['a1', 'sub1'])
66
tree.commit('initial commit')
67
self.assertEqual([('a1', 'sub1/a1')],
68
tree.move(['a1'], 'sub1', after=False))
70
def test_move_deprecated_wrong_call(self):
71
"""tree.move has the deprecated parameter 'to_name'.
72
It has been replaced by 'to_dir' for consistency.
73
Test the new API using wrong parameter
75
self.build_tree(['a1', 'sub1/'])
76
tree = self.make_branch_and_tree('.')
77
tree.add(['a1', 'sub1'])
78
tree.commit('initial commit')
79
self.assertRaises(TypeError, tree.move, ['a1'],
80
to_this_parameter_does_not_exist='sub1',
83
def test_move_deprecated_call(self):
84
"""tree.move has the deprecated parameter 'to_name'.
85
It has been replaced by 'to_dir' for consistency.
86
Test the new API using deprecated parameter
88
self.build_tree(['a1', 'sub1/'])
89
tree = self.make_branch_and_tree('.')
90
tree.add(['a1', 'sub1'])
91
tree.commit('initial commit')
94
self.callDeprecated(['The parameter to_name was deprecated'
95
' in version 0.13. Use to_dir instead'],
96
tree.move, ['a1'], to_name='sub1',
99
# WorkingTreeFormat4 doesn't have to maintain api compatibility
100
# since it was deprecated before the class was introduced.
101
if not isinstance(self.workingtree_format, WorkingTreeFormat4):
104
def test_move_target_not_dir(self):
105
tree = self.make_branch_and_tree('.')
106
self.build_tree(['a'])
108
tree.commit('initial', rev_id='rev-1')
110
self.assertRaises(errors.BzrMoveFailedError,
111
tree.move, ['a'], 'not-a-dir')
113
def test_move_non_existent(self):
114
tree = self.make_branch_and_tree('.')
115
self.build_tree(['a/'])
117
tree.commit('initial', rev_id='rev-1')
118
self.assertRaises(errors.BzrMoveFailedError,
119
tree.move, ['not-a-file'], 'a')
120
self.assertRaises(errors.BzrMoveFailedError,
121
tree.move, ['not-a-file'], '')
123
def test_move_target_not_versioned(self):
124
tree = self.make_branch_and_tree('.')
125
self.build_tree(['a/', 'b'])
127
tree.commit('initial', rev_id='rev-1')
128
self.assertRaises(errors.BzrMoveFailedError,
129
tree.move, ['b'], 'a')
131
def test_move_unversioned(self):
132
tree = self.make_branch_and_tree('.')
133
self.build_tree(['a/', 'b'])
135
tree.commit('initial', rev_id='rev-1')
136
self.assertRaises(errors.BzrMoveFailedError,
137
tree.move, ['b'], 'a')
139
def test_move_multi_unversioned(self):
140
tree = self.make_branch_and_tree('.')
141
self.build_tree(['a/', 'b', 'c', 'd'])
142
tree.add(['a', 'c', 'd'], ['a-id', 'c-id', 'd-id'])
143
tree.commit('initial', rev_id='rev-1')
144
root_id = tree.get_root_id()
145
self.assertRaises(errors.BzrMoveFailedError,
146
tree.move, ['c', 'b', 'd'], 'a')
147
self.assertRaises(errors.BzrMoveFailedError,
148
tree.move, ['b', 'c', 'd'], 'a')
149
self.assertRaises(errors.BzrMoveFailedError,
150
tree.move, ['d', 'c', 'b'], 'a')
151
if osutils.lexists('a/c'):
152
# If 'c' was actually moved, then 'd' should have also been moved
153
self.assertTreeLayout([('', root_id), ('a', 'a-id'),
154
('a/c', 'c-id'), ('a/d', 'd-id')], tree)
156
self.assertTreeLayout([('', root_id), ('a', 'a-id'), ('c', 'c-id'),
157
('d', 'd-id')], tree)
158
self.assertTreeLayout([('', root_id), ('a', 'a-id'), ('c', 'c-id'),
159
('d', 'd-id')], tree.basis_tree())
161
def test_move_subdir(self):
162
tree = self.make_branch_and_tree('.')
163
self.build_tree(['a', 'b/', 'b/c'])
164
tree.add(['a', 'b', 'b/c'], ['a-id', 'b-id', 'c-id'])
165
tree.commit('initial', rev_id='rev-1')
166
root_id = tree.get_root_id()
167
self.assertTreeLayout([('', root_id), ('a', 'a-id'), ('b', 'b-id'),
168
('b/c', 'c-id')], tree)
169
self.assertTreeLayout([('', root_id), ('a', 'a-id'), ('b', 'b-id'),
170
('b/c', 'c-id')], tree.basis_tree())
171
a_contents = tree.get_file_text('a-id')
172
self.assertEqual([('a', 'b/a')],
173
tree.move(['a'], 'b'))
174
self.assertTreeLayout([('', root_id), ('b', 'b-id'), ('b/a', 'a-id'),
175
('b/c', 'c-id')], tree)
176
self.assertTreeLayout([('', root_id), ('a', 'a-id'), ('b', 'b-id'),
177
('b/c', 'c-id')], tree.basis_tree())
178
self.failIfExists('a')
179
self.assertFileEqual(a_contents, 'b/a')
181
def test_move_parent_dir(self):
182
tree = self.make_branch_and_tree('.')
183
self.build_tree(['a', 'b/', 'b/c'])
184
tree.add(['a', 'b', 'b/c'], ['a-id', 'b-id', 'c-id'])
185
tree.commit('initial', rev_id='rev-1')
186
root_id = tree.get_root_id()
187
c_contents = tree.get_file_text('c-id')
188
self.assertEqual([('b/c', 'c')],
189
tree.move(['b/c'], ''))
190
self.assertTreeLayout([('', root_id), ('a', 'a-id'), ('b', 'b-id'),
191
('c', 'c-id')], tree)
192
self.assertTreeLayout([('', root_id), ('a', 'a-id'), ('b', 'b-id'),
193
('b/c', 'c-id')], tree.basis_tree())
194
self.failIfExists('b/c')
195
self.assertFileEqual(c_contents, 'c')
197
def test_move_fail_consistent(self):
198
tree = self.make_branch_and_tree('.')
199
self.build_tree(['a', 'b/', 'b/a', 'c'])
200
tree.add(['a', 'b', 'c'], ['a-id', 'b-id', 'c-id'])
201
tree.commit('initial', rev_id='rev-1')
202
root_id = tree.get_root_id()
203
# Target already exists
204
self.assertRaises(errors.RenameFailedFilesExist,
205
tree.move, ['c', 'a'], 'b')
206
# 'c' may or may not have been moved, but either way the tree should
207
# maintain a consistent state.
208
if osutils.lexists('c'):
209
self.assertTreeLayout([('', root_id), ('a', 'a-id'), ('b', 'b-id'),
210
('c', 'c-id')], tree)
212
self.failUnlessExists('b/c')
213
self.assertTreeLayout([('', root_id), ('a', 'a-id'), ('b', 'b-id'),
214
('b/c', 'c-id')], tree)
215
self.assertTreeLayout([('', root_id), ('a', 'a-id'), ('b', 'b-id'),
216
('c', 'c-id')], tree.basis_tree())
218
def test_move_onto_self(self):
219
tree = self.make_branch_and_tree('.')
220
self.build_tree(['b/', 'b/a'])
221
tree.add(['b', 'b/a'], ['b-id', 'a-id'])
222
tree.commit('initial', rev_id='rev-1')
224
self.assertRaises(errors.BzrMoveFailedError,
225
tree.move, ['b/a'], 'b')
227
def test_move_onto_self_root(self):
228
tree = self.make_branch_and_tree('.')
229
self.build_tree(['a'])
230
tree.add(['a'], ['a-id'])
231
tree.commit('initial', rev_id='rev-1')
233
self.assertRaises(errors.BzrMoveFailedError,
234
tree.move, ['a'], 'a')
236
def test_move_after(self):
237
tree = self.make_branch_and_tree('.')
238
self.build_tree(['a', 'b/'])
239
tree.add(['a', 'b'], ['a-id', 'b-id'])
240
tree.commit('initial', rev_id='rev-1')
241
root_id = tree.get_root_id()
242
os.rename('a', 'b/a')
244
self.assertTreeLayout([('', root_id), ('a', 'a-id'), ('b', 'b-id')],
246
# We don't need after=True as long as source is missing and target
248
self.assertEqual([('a', 'b/a')],
249
tree.move(['a'], 'b'))
250
self.assertTreeLayout([('', root_id), ('b', 'b-id'), ('b/a', 'a-id')],
252
self.assertTreeLayout([('', root_id), ('a', 'a-id'), ('b', 'b-id')],
255
def test_move_after_with_after(self):
256
tree = self.make_branch_and_tree('.')
257
self.build_tree(['a', 'b/'])
258
tree.add(['a', 'b'], ['a-id', 'b-id'])
259
tree.commit('initial', rev_id='rev-1')
260
root_id = tree.get_root_id()
261
os.rename('a', 'b/a')
263
self.assertTreeLayout([('', root_id), ('a', 'a-id'), ('b', 'b-id')],
265
# Passing after=True should work as well
266
self.assertEqual([('a', 'b/a')],
267
tree.move(['a'], 'b', after=True))
268
self.assertTreeLayout([('', root_id), ('b', 'b-id'), ('b/a', 'a-id')],
270
self.assertTreeLayout([('', root_id), ('a', 'a-id'), ('b', 'b-id')],
273
def test_move_after_no_target(self):
274
tree = self.make_branch_and_tree('.')
275
self.build_tree(['a', 'b/'])
276
tree.add(['a', 'b'], ['a-id', 'b-id'])
277
tree.commit('initial', rev_id='rev-1')
278
root_id = tree.get_root_id()
280
# Passing after when the file hasn't been move raises an exception
281
self.assertRaises(errors.BzrMoveFailedError,
282
tree.move, ['a'], 'b', after=True)
283
self.assertTreeLayout([('', root_id), ('a', 'a-id'), ('b', 'b-id')],
286
def test_move_after_source_and_dest(self):
287
tree = self.make_branch_and_tree('.')
288
self.build_tree(['a', 'b/', 'b/a'])
289
tree.add(['a', 'b'], ['a-id', 'b-id'])
290
tree.commit('initial', rev_id='rev-1')
291
root_id = tree.get_root_id()
293
# TODO: jam 20070225 I would usually use 'rb', but assertFileEqual
295
a_file = open('a', 'r')
297
a_text = a_file.read()
300
ba_file = open('b/a', 'r')
302
ba_text = ba_file.read()
306
self.assertTreeLayout([('', root_id), ('a', 'a-id'), ('b', 'b-id')],
308
self.assertRaises(errors.RenameFailedFilesExist,
309
tree.move, ['a'], 'b', after=False)
310
self.assertTreeLayout([('', root_id), ('a', 'a-id'), ('b', 'b-id')],
312
self.assertFileEqual(a_text, 'a')
313
self.assertFileEqual(ba_text, 'b/a')
314
# But you can pass after=True
315
self.assertEqual([('a', 'b/a')],
316
tree.move(['a'], 'b', after=True))
317
self.assertTreeLayout([('', root_id), ('b', 'b-id'), ('b/a', 'a-id')],
319
self.assertTreeLayout([('', root_id), ('a', 'a-id'), ('b', 'b-id')],
321
# But it shouldn't actually move anything
322
self.assertFileEqual(a_text, 'a')
323
self.assertFileEqual(ba_text, 'b/a')
325
def test_move_directory(self):
326
tree = self.make_branch_and_tree('.')
327
self.build_tree(['a/', 'a/b', 'a/c/', 'a/c/d', 'e/'])
328
tree.add(['a', 'a/b', 'a/c', 'a/c/d', 'e'],
329
['a-id', 'b-id', 'c-id', 'd-id', 'e-id'])
330
tree.commit('initial', rev_id='rev-1')
331
root_id = tree.get_root_id()
333
self.assertEqual([('a', 'e/a')],
334
tree.move(['a'], 'e'))
335
self.assertTreeLayout([('', root_id), ('e', 'e-id'), ('e/a', 'a-id'),
336
('e/a/b', 'b-id'), ('e/a/c', 'c-id'),
337
('e/a/c/d', 'd-id')], tree)
338
self.assertTreeLayout([('', root_id), ('a', 'a-id'), ('e', 'e-id'),
339
('a/b', 'b-id'), ('a/c', 'c-id'),
340
('a/c/d', 'd-id')], tree.basis_tree())
342
def test_move_moved(self):
343
"""Moving a moved entry works as expected."""
344
tree = self.make_branch_and_tree('.')
345
self.build_tree(['a/', 'a/b', 'c/'])
346
tree.add(['a', 'a/b', 'c'], ['a-id', 'b-id', 'c-id'])
347
tree.commit('initial', rev_id='rev-1')
348
root_id = tree.get_root_id()
350
self.assertEqual([('a/b', 'c/b')],
351
tree.move(['a/b'], 'c'))
352
self.assertTreeLayout([('', root_id), ('a', 'a-id'), ('c', 'c-id'),
353
('c/b', 'b-id')], tree)
354
self.assertTreeLayout([('', root_id), ('a', 'a-id'), ('c', 'c-id'),
355
('a/b', 'b-id')], tree.basis_tree())
357
self.assertEqual([('c/b', 'b')],
358
tree.move(['c/b'], ''))
359
self.assertTreeLayout([('', root_id), ('a', 'a-id'), ('b', 'b-id'),
360
('c', 'c-id')], tree)
361
self.assertTreeLayout([('', root_id), ('a', 'a-id'), ('c', 'c-id'),
362
('a/b', 'b-id')], tree.basis_tree())