21
21
from bzrlib import (
27
from bzrlib.tests.matchers import HasLayout
26
from bzrlib.workingtree_4 import DirStateWorkingTreeFormat
28
27
from bzrlib.tests.per_workingtree import TestCaseWithWorkingTree
29
from bzrlib.tests import (
34
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()]
36
41
def assertTreeLayout(self, expected, tree):
37
42
"""Check that the tree has the correct layout."""
38
self.assertThat(tree, HasLayout(expected))
43
actual = self.get_tree_layout(tree)
44
self.assertEqual(expected, actual)
40
46
def test_move_via_rm_and_add(self):
41
47
"""Move by remove and add-with-id"""
126
132
tree.move, ['d', 'c', 'b'], 'a')
127
133
if osutils.lexists('a/c'):
128
134
# If 'c' was actually moved, then 'd' should have also been moved
129
self.assertTreeLayout([('', root_id), ('a/', 'a-id'),
135
self.assertTreeLayout([('', root_id), ('a', 'a-id'),
130
136
('a/c', 'c-id'), ('a/d', 'd-id')], tree)
132
self.assertTreeLayout([('', root_id), ('a/', 'a-id'), ('c', 'c-id'),
138
self.assertTreeLayout([('', root_id), ('a', 'a-id'), ('c', 'c-id'),
133
139
('d', 'd-id')], tree)
134
self.assertTreeLayout([('', root_id), ('a/', 'a-id'), ('c', 'c-id'),
140
self.assertTreeLayout([('', root_id), ('a', 'a-id'), ('c', 'c-id'),
135
141
('d', 'd-id')], tree.basis_tree())
156
162
tree.add(['a', 'b', 'b/c'], ['a-id', 'b-id', 'c-id'])
157
163
tree.commit('initial', rev_id='rev-1')
158
164
root_id = tree.get_root_id()
159
self.assertTreeLayout([('', root_id), ('a', 'a-id'), ('b/', 'b-id'),
165
self.assertTreeLayout([('', root_id), ('a', 'a-id'), ('b', 'b-id'),
160
166
('b/c', 'c-id')], tree)
161
self.assertTreeLayout([('', root_id), ('a', 'a-id'), ('b/', 'b-id'),
167
self.assertTreeLayout([('', root_id), ('a', 'a-id'), ('b', 'b-id'),
162
168
('b/c', 'c-id')], tree.basis_tree())
163
169
a_contents = tree.get_file_text('a-id')
164
170
self.assertEqual([('a', 'b/a')],
165
171
tree.move(['a'], 'b'))
166
self.assertTreeLayout([('', root_id), ('b/', 'b-id'), ('b/a', 'a-id'),
172
self.assertTreeLayout([('', root_id), ('b', 'b-id'), ('b/a', 'a-id'),
167
173
('b/c', 'c-id')], tree)
168
self.assertTreeLayout([('', root_id), ('a', 'a-id'), ('b/', 'b-id'),
174
self.assertTreeLayout([('', root_id), ('a', 'a-id'), ('b', 'b-id'),
169
175
('b/c', 'c-id')], tree.basis_tree())
170
self.assertPathDoesNotExist('a')
176
self.failIfExists('a')
171
177
self.assertFileEqual(a_contents, 'b/a')
180
186
c_contents = tree.get_file_text('c-id')
181
187
self.assertEqual([('b/c', 'c')],
182
188
tree.move(['b/c'], ''))
183
self.assertTreeLayout([('', root_id), ('a', 'a-id'), ('b/', 'b-id'),
189
self.assertTreeLayout([('', root_id), ('a', 'a-id'), ('b', 'b-id'),
184
190
('c', 'c-id')], tree)
185
self.assertTreeLayout([('', root_id), ('a', 'a-id'), ('b/', 'b-id'),
191
self.assertTreeLayout([('', root_id), ('a', 'a-id'), ('b', 'b-id'),
186
192
('b/c', 'c-id')], tree.basis_tree())
187
self.assertPathDoesNotExist('b/c')
193
self.failIfExists('b/c')
188
194
self.assertFileEqual(c_contents, 'c')
200
206
# 'c' may or may not have been moved, but either way the tree should
201
207
# maintain a consistent state.
202
208
if osutils.lexists('c'):
203
self.assertTreeLayout([('', root_id), ('a', 'a-id'), ('b/', 'b-id'),
209
self.assertTreeLayout([('', root_id), ('a', 'a-id'), ('b', 'b-id'),
204
210
('c', 'c-id')], tree)
206
self.assertPathExists('b/c')
207
self.assertTreeLayout([('', root_id), ('a', 'a-id'), ('b/', 'b-id'),
212
self.failUnlessExists('b/c')
213
self.assertTreeLayout([('', root_id), ('a', 'a-id'), ('b', 'b-id'),
208
214
('b/c', 'c-id')], tree)
209
self.assertTreeLayout([('', root_id), ('a', 'a-id'), ('b/', 'b-id'),
215
self.assertTreeLayout([('', root_id), ('a', 'a-id'), ('b', 'b-id'),
210
216
('c', 'c-id')], tree.basis_tree())
238
244
root_id = tree.get_root_id()
239
245
os.rename('a', 'b/a')
241
self.assertTreeLayout([('', root_id), ('a', 'a-id'), ('b/', 'b-id')],
247
self.assertTreeLayout([('', root_id), ('a', 'a-id'), ('b', 'b-id')],
243
249
# We don't need after=True as long as source is missing and target
245
251
self.assertEqual([('a', 'b/a')],
246
252
tree.move(['a'], 'b'))
247
self.assertTreeLayout([('', root_id), ('b/', 'b-id'), ('b/a', 'a-id')],
253
self.assertTreeLayout([('', root_id), ('b', 'b-id'), ('b/a', 'a-id')],
249
self.assertTreeLayout([('', root_id), ('a', 'a-id'), ('b/', 'b-id')],
255
self.assertTreeLayout([('', root_id), ('a', 'a-id'), ('b', 'b-id')],
250
256
tree.basis_tree())
258
264
root_id = tree.get_root_id()
259
265
os.rename('a', 'b/a')
261
self.assertTreeLayout([('', root_id), ('a', 'a-id'), ('b/', 'b-id')],
267
self.assertTreeLayout([('', root_id), ('a', 'a-id'), ('b', 'b-id')],
263
269
# Passing after=True should work as well
264
270
self.assertEqual([('a', 'b/a')],
265
271
tree.move(['a'], 'b', after=True))
266
self.assertTreeLayout([('', root_id), ('b/', 'b-id'), ('b/a', 'a-id')],
272
self.assertTreeLayout([('', root_id), ('b', 'b-id'), ('b/a', 'a-id')],
268
self.assertTreeLayout([('', root_id), ('a', 'a-id'), ('b/', 'b-id')],
274
self.assertTreeLayout([('', root_id), ('a', 'a-id'), ('b', 'b-id')],
269
275
tree.basis_tree())
279
285
# Passing after when the file hasn't been move raises an exception
280
286
self.assertRaises(errors.BzrMoveFailedError,
281
287
tree.move, ['a'], 'b', after=True)
282
self.assertTreeLayout([('', root_id), ('a', 'a-id'), ('b/', 'b-id')],
288
self.assertTreeLayout([('', root_id), ('a', 'a-id'), ('b', 'b-id')],
283
289
tree.basis_tree())
306
self.assertTreeLayout([('', root_id), ('a', 'a-id'), ('b/', 'b-id')],
312
self.assertTreeLayout([('', root_id), ('a', 'a-id'), ('b', 'b-id')],
308
314
self.assertRaises(errors.RenameFailedFilesExist,
309
315
tree.move, ['a'], 'b', after=False)
310
self.assertTreeLayout([('', root_id), ('a', 'a-id'), ('b/', 'b-id')],
316
self.assertTreeLayout([('', root_id), ('a', 'a-id'), ('b', 'b-id')],
312
318
self.assertFileEqual(a_text, 'a')
313
319
self.assertFileEqual(ba_text, 'b/a')
314
320
# But you can pass after=True
315
321
self.assertEqual([('a', 'b/a')],
316
322
tree.move(['a'], 'b', after=True))
317
self.assertTreeLayout([('', root_id), ('b/', 'b-id'), ('b/a', 'a-id')],
323
self.assertTreeLayout([('', root_id), ('b', 'b-id'), ('b/a', 'a-id')],
319
self.assertTreeLayout([('', root_id), ('a', 'a-id'), ('b/', 'b-id')],
325
self.assertTreeLayout([('', root_id), ('a', 'a-id'), ('b', 'b-id')],
320
326
tree.basis_tree())
321
327
# But it shouldn't actually move anything
322
328
self.assertFileEqual(a_text, 'a')
334
340
self.assertEqual([('a', 'e/a')],
335
341
tree.move(['a'], 'e'))
336
self.assertTreeLayout([('', root_id), ('e/', 'e-id'), ('e/a/', 'a-id'),
337
('e/a/b', 'b-id'), ('e/a/c/', 'c-id'),
342
self.assertTreeLayout([('', root_id), ('e', 'e-id'), ('e/a', 'a-id'),
343
('e/a/b', 'b-id'), ('e/a/c', 'c-id'),
338
344
('e/a/c/d', 'd-id')], tree)
339
self.assertTreeLayout([('', root_id), ('a/', 'a-id'), ('e/', 'e-id'),
340
('a/b', 'b-id'), ('a/c/', 'c-id'),
345
self.assertTreeLayout([('', root_id), ('a', 'a-id'), ('e', 'e-id'),
346
('a/b', 'b-id'), ('a/c', 'c-id'),
341
347
('a/c/d', 'd-id')], tree.basis_tree())
344
350
def test_move_directory_into_parent(self):
345
if not self.workingtree_format.supports_versioned_directories:
346
raise tests.TestNotApplicable(
347
"test requires versioned directories")
348
351
tree = self.make_branch_and_tree('.')
349
352
self.build_tree(['c/', 'c/b/', 'c/b/d/'])
350
353
tree.add(['c', 'c/b', 'c/b/d'],
369
372
tree.commit('initial', rev_id='rev-1')
370
373
root_id = tree.get_root_id()
372
376
tree.rename_one('a/b', 'a/c/b')
373
377
self.assertTreeLayout([('', root_id),
377
381
('a/c/b', 'b-id'),
379
383
self.assertEqual([('a', 'd/a')],
380
384
tree.move(['a'], 'd'))
381
385
self.assertTreeLayout([('', root_id),
385
389
('d/a/c/b', 'b-id'),
528
532
self.assertEqual([('a/b', 'c/b')],
529
533
tree.move(['a/b'], 'c'))
530
self.assertTreeLayout([('', root_id), ('a/', 'a-id'), ('c/', 'c-id'),
534
self.assertTreeLayout([('', root_id), ('a', 'a-id'), ('c', 'c-id'),
531
535
('c/b', 'b-id')], tree)
532
self.assertTreeLayout([('', root_id), ('a/', 'a-id'), ('c/', 'c-id'),
536
self.assertTreeLayout([('', root_id), ('a', 'a-id'), ('c', 'c-id'),
533
537
('a/b', 'b-id')], tree.basis_tree())
535
539
self.assertEqual([('c/b', 'b')],
536
540
tree.move(['c/b'], ''))
537
self.assertTreeLayout([('', root_id), ('a/', 'a-id'), ('b', 'b-id'),
538
('c/', 'c-id')], tree)
539
self.assertTreeLayout([('', root_id), ('a/', 'a-id'), ('c/', 'c-id'),
541
self.assertTreeLayout([('', root_id), ('a', 'a-id'), ('b', 'b-id'),
542
('c', 'c-id')], tree)
543
self.assertTreeLayout([('', root_id), ('a', 'a-id'), ('c', 'c-id'),
540
544
('a/b', 'b-id')], tree.basis_tree())
543
def test_move_to_unversioned_non_ascii_dir(self):
544
"""Check error when moving to unversioned non-ascii directory"""
545
self.requireFeature(features.UnicodeFilenameFeature)
546
tree = self.make_branch_and_tree(".")
547
self.build_tree(["a", u"\xA7/"])
549
e = self.assertRaises(errors.BzrMoveFailedError,
550
tree.move, ["a"], u"\xA7")
551
self.assertIsInstance(e.extra, errors.NotVersionedError)
552
self.assertEqual(e.extra.path, u"\xA7")
554
def test_move_unversioned_non_ascii(self):
555
"""Check error when moving an unversioned non-ascii file"""
556
self.requireFeature(features.UnicodeFilenameFeature)
557
tree = self.make_branch_and_tree(".")
558
self.build_tree([u"\xA7", "dir/"])
560
e = self.assertRaises(errors.BzrMoveFailedError,
561
tree.move, [u"\xA7"], "dir")
562
self.assertIsInstance(e.extra, errors.NotVersionedError)
563
self.assertEqual(e.extra.path, u"\xA7")