26
from bzrlib.tests import (
29
from bzrlib.tests.matchers import HasLayout
27
31
from bzrlib.tests.per_workingtree import TestCaseWithWorkingTree
30
34
class TestRenameOne(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
36
def assertTreeLayout(self, expected, tree):
42
37
"""Check that the tree has the correct layout."""
43
actual = self.get_tree_layout(tree)
44
self.assertEqual(expected, actual)
38
self.assertThat(tree, HasLayout(expected))
46
40
def test_rename_one_target_not_dir(self):
47
41
tree = self.make_branch_and_tree('.')
88
82
a_contents = tree.get_file_text('a-id')
89
83
tree.rename_one('a', 'foo')
90
self.assertTreeLayout([('', root_id), ('b', 'b-id'), ('foo', 'a-id')],
84
self.assertTreeLayout([('', root_id), ('b/', 'b-id'), ('foo', 'a-id')],
92
self.assertTreeLayout([('', root_id), ('a', 'a-id'), ('b', 'b-id')],
86
self.assertTreeLayout([('', root_id), ('a', 'a-id'), ('b/', 'b-id')],
94
self.failIfExists('a')
88
self.assertPathDoesNotExist('a')
95
89
self.assertFileEqual(a_contents, 'foo')
97
91
def test_rename_one_not_localdir(self):
104
98
a_contents = tree.get_file_text('a-id')
105
99
tree.rename_one('a', 'b/foo')
106
self.assertTreeLayout([('', root_id), ('b', 'b-id'), ('b/foo', 'a-id')],
100
self.assertTreeLayout([('', root_id), ('b/', 'b-id'), ('b/foo', 'a-id')],
108
self.assertTreeLayout([('', root_id), ('a', 'a-id'), ('b', 'b-id')],
102
self.assertTreeLayout([('', root_id), ('a', 'a-id'), ('b/', 'b-id')],
109
103
tree.basis_tree())
110
self.failIfExists('tree/a')
104
self.assertPathDoesNotExist('tree/a')
111
105
self.assertFileEqual(a_contents, 'tree/b/foo')
113
107
def test_rename_one_subdir(self):
116
110
tree.add(['a', 'b', 'b/c'], ['a-id', 'b-id', 'c-id'])
117
111
tree.commit('initial', rev_id='rev-1')
118
112
root_id = tree.get_root_id()
119
self.assertTreeLayout([('', root_id), ('a', 'a-id'), ('b', 'b-id'),
113
self.assertTreeLayout([('', root_id), ('a', 'a-id'), ('b/', 'b-id'),
120
114
('b/c', 'c-id')], tree)
121
self.assertTreeLayout([('', root_id), ('a', 'a-id'), ('b', 'b-id'),
115
self.assertTreeLayout([('', root_id), ('a', 'a-id'), ('b/', 'b-id'),
122
116
('b/c', 'c-id')], tree.basis_tree())
123
117
a_contents = tree.get_file_text('a-id')
124
118
tree.rename_one('a', 'b/d')
125
self.assertTreeLayout([('', root_id), ('b', 'b-id'), ('b/c', 'c-id'),
119
self.assertTreeLayout([('', root_id), ('b/', 'b-id'), ('b/c', 'c-id'),
126
120
('b/d', 'a-id')], tree)
127
self.assertTreeLayout([('', root_id), ('a', 'a-id'), ('b', 'b-id'),
121
self.assertTreeLayout([('', root_id), ('a', 'a-id'), ('b/', 'b-id'),
128
122
('b/c', 'c-id')], tree.basis_tree())
129
self.failIfExists('a')
123
self.assertPathDoesNotExist('a')
130
124
self.assertFileEqual(a_contents, 'b/d')
132
126
def test_rename_one_parent_dir(self):
137
131
root_id = tree.get_root_id()
138
132
c_contents = tree.get_file_text('c-id')
139
133
tree.rename_one('b/c', 'd')
140
self.assertTreeLayout([('', root_id), ('a', 'a-id'), ('b', 'b-id'),
134
self.assertTreeLayout([('', root_id), ('a', 'a-id'), ('b/', 'b-id'),
141
135
('d', 'c-id')], tree)
142
self.assertTreeLayout([('', root_id), ('a', 'a-id'), ('b', 'b-id'),
136
self.assertTreeLayout([('', root_id), ('a', 'a-id'), ('b/', 'b-id'),
143
137
('b/c', 'c-id')], tree.basis_tree())
144
self.failIfExists('b/c')
138
self.assertPathDoesNotExist('b/c')
145
139
self.assertFileEqual(c_contents, 'd')
147
141
def test_rename_one_fail_consistent(self):
153
147
# Target already exists
154
148
self.assertRaises(errors.RenameFailedFilesExist,
155
149
tree.rename_one, 'a', 'b/a')
156
self.assertTreeLayout([('', root_id), ('a', 'a-id'), ('b', 'b-id'),
150
self.assertTreeLayout([('', root_id), ('a', 'a-id'), ('b/', 'b-id'),
157
151
('c', 'c-id')], tree)
158
self.assertTreeLayout([('', root_id), ('a', 'a-id'), ('b', 'b-id'),
152
self.assertTreeLayout([('', root_id), ('a', 'a-id'), ('b/', 'b-id'),
159
153
('c', 'c-id')], tree.basis_tree())
161
155
def test_rename_one_onto_existing(self):
193
187
root_id = tree.get_root_id()
194
188
os.rename('a', 'b/foo')
196
self.assertTreeLayout([('', root_id), ('a', 'a-id'), ('b', 'b-id')],
190
self.assertTreeLayout([('', root_id), ('a', 'a-id'), ('b/', 'b-id')],
198
192
# We don't need after=True as long as source is missing and target
200
194
tree.rename_one('a', 'b/foo')
201
self.assertTreeLayout([('', root_id), ('b', 'b-id'),
195
self.assertTreeLayout([('', root_id), ('b/', 'b-id'),
202
196
('b/foo', 'a-id')], tree)
203
self.assertTreeLayout([('', root_id), ('a', 'a-id'), ('b', 'b-id')],
197
self.assertTreeLayout([('', root_id), ('a', 'a-id'), ('b/', 'b-id')],
204
198
tree.basis_tree())
206
200
def test_rename_one_after_with_after(self):
211
205
root_id = tree.get_root_id()
212
206
os.rename('a', 'b/foo')
214
self.assertTreeLayout([('', root_id), ('a', 'a-id'), ('b', 'b-id')],
208
self.assertTreeLayout([('', root_id), ('a', 'a-id'), ('b/', 'b-id')],
216
210
# Passing after=True should work as well
217
211
tree.rename_one('a', 'b/foo', after=True)
218
self.assertTreeLayout([('', root_id), ('b', 'b-id'),
212
self.assertTreeLayout([('', root_id), ('b/', 'b-id'),
219
213
('b/foo', 'a-id')], tree)
220
self.assertTreeLayout([('', root_id), ('a', 'a-id'), ('b', 'b-id')],
214
self.assertTreeLayout([('', root_id), ('a', 'a-id'), ('b/', 'b-id')],
221
215
tree.basis_tree())
217
def test_rename_one_after_dest_versioned(self):
218
tree = self.make_branch_and_tree('.')
219
self.build_tree(['a'])
220
tree.add(['a'], ['a-id'])
221
tree.commit('initial', rev_id='rev-1')
222
root_id = tree.get_root_id()
224
tree.add(['b'], ['b-id'])
226
self.assertTreeLayout([('', root_id), ('a', 'a-id'), ('b', 'b-id')],
228
e = self.assertRaises(errors.BzrMoveFailedError,
229
tree.rename_one, 'a', 'b')
230
self.assertIsInstance(e.extra, errors.AlreadyVersionedError)
232
def test_rename_one_after_with_after_dest_versioned(self):
233
''' using after with an already versioned file should fail '''
234
tree = self.make_branch_and_tree('.')
235
self.build_tree(['a', 'b'])
236
tree.add(['a', 'b'], ['a-id', 'b-id'])
237
tree.commit('initial', rev_id='rev-1')
238
root_id = tree.get_root_id()
241
self.assertTreeLayout([('', root_id), ('a', 'a-id'), ('b', 'b-id')],
243
e = self.assertRaises(errors.BzrMoveFailedError,
244
tree.rename_one, 'a', 'b', after=True)
245
self.assertIsInstance(e.extra, errors.AlreadyVersionedError)
247
def test_rename_one_after_with_after_dest_added(self):
248
''' using after with a newly added file should work '''
249
tree = self.make_branch_and_tree('.')
250
self.build_tree(['a'])
251
tree.add(['a'], ['a-id'])
252
tree.commit('initial', rev_id='rev-1')
253
root_id = tree.get_root_id()
255
tree.add(['b'], ['b-id'])
257
self.assertTreeLayout([('', root_id), ('a', 'a-id'), ('b', 'b-id')],
259
tree.rename_one('a', 'b', after=True)
260
self.assertTreeLayout([('', root_id), ('b', 'a-id')], tree)
223
262
def test_rename_one_after_source_removed(self):
224
"""Rename even if the source was removed from the inventory already"""
263
"""Rename even if the source was already unversioned."""
225
264
tree = self.make_branch_and_tree('.')
226
265
self.build_tree(['a', 'b/'])
227
266
tree.add(['a', 'b'], ['a-id', 'b-id'])
230
269
os.rename('a', 'b/foo')
231
270
tree.remove(['a'])
233
self.assertTreeLayout([('', root_id), ('b', 'b-id')], tree)
272
self.assertTreeLayout([('', root_id), ('b/', 'b-id')], tree)
234
273
# We don't need after=True as long as source is missing and target
236
275
tree.rename_one('a', 'b/foo')
237
self.assertTreeLayout([('', root_id), ('b', 'b-id'),
276
self.assertTreeLayout([('', root_id), ('b/', 'b-id'),
238
277
('b/foo', 'a-id')], tree)
239
self.assertTreeLayout([('', root_id), ('a', 'a-id'), ('b', 'b-id')],
278
self.assertTreeLayout([('', root_id), ('a', 'a-id'), ('b/', 'b-id')],
240
279
tree.basis_tree())
242
281
def test_rename_one_after_no_target(self):
249
288
# Passing after when the file hasn't been rename_one raises an exception
250
289
self.assertRaises(errors.BzrMoveFailedError,
251
290
tree.rename_one, 'a', 'b/foo', after=True)
252
self.assertTreeLayout([('', root_id), ('a', 'a-id'), ('b', 'b-id')],
291
self.assertTreeLayout([('', root_id), ('a', 'a-id'), ('b/', 'b-id')],
254
self.assertTreeLayout([('', root_id), ('a', 'a-id'), ('b', 'b-id')],
293
self.assertTreeLayout([('', root_id), ('a', 'a-id'), ('b/', 'b-id')],
255
294
tree.basis_tree())
257
296
def test_rename_one_after_source_and_dest(self):
277
self.assertTreeLayout([('', root_id), ('a', 'a-id'), ('b', 'b-id')],
316
self.assertTreeLayout([('', root_id), ('a', 'a-id'), ('b/', 'b-id')],
279
318
self.assertRaises(errors.RenameFailedFilesExist,
280
319
tree.rename_one, 'a', 'b/foo', after=False)
281
self.assertTreeLayout([('', root_id), ('a', 'a-id'), ('b', 'b-id')],
320
self.assertTreeLayout([('', root_id), ('a', 'a-id'), ('b/', 'b-id')],
283
322
self.assertFileEqual(a_text, 'a')
284
323
self.assertFileEqual(foo_text, 'b/foo')
285
324
# But you can pass after=True
286
325
tree.rename_one('a', 'b/foo', after=True)
287
self.assertTreeLayout([('', root_id), ('b', 'b-id'),
326
self.assertTreeLayout([('', root_id), ('b/', 'b-id'),
288
327
('b/foo', 'a-id')], tree)
289
self.assertTreeLayout([('', root_id), ('a', 'a-id'), ('b', 'b-id')],
328
self.assertTreeLayout([('', root_id), ('a', 'a-id'), ('b/', 'b-id')],
290
329
tree.basis_tree())
291
330
# But it shouldn't actually move anything
292
331
self.assertFileEqual(a_text, 'a')
301
340
root_id = tree.get_root_id()
303
342
tree.rename_one('a', 'e/f')
304
self.assertTreeLayout([('', root_id), ('e', 'e-id'), ('e/f', 'a-id'),
305
('e/f/b', 'b-id'), ('e/f/c', 'c-id'),
343
self.assertTreeLayout([('', root_id), ('e/', 'e-id'), ('e/f/', 'a-id'),
344
('e/f/b', 'b-id'), ('e/f/c/', 'c-id'),
306
345
('e/f/c/d', 'd-id')], tree)
307
self.assertTreeLayout([('', root_id), ('a', 'a-id'), ('e', 'e-id'),
308
('a/b', 'b-id'), ('a/c', 'c-id'),
346
self.assertTreeLayout([('', root_id), ('a/', 'a-id'), ('e/', 'e-id'),
347
('a/b', 'b-id'), ('a/c/', 'c-id'),
309
348
('a/c/d', 'd-id')], tree.basis_tree())
311
350
def test_rename_one_moved(self):
317
356
root_id = tree.get_root_id()
319
358
tree.rename_one('a/b', 'c/foo')
320
self.assertTreeLayout([('', root_id), ('a', 'a-id'), ('c', 'c-id'),
359
self.assertTreeLayout([('', root_id), ('a/', 'a-id'), ('c/', 'c-id'),
321
360
('c/foo', 'b-id')], tree)
322
self.assertTreeLayout([('', root_id), ('a', 'a-id'), ('c', 'c-id'),
361
self.assertTreeLayout([('', root_id), ('a/', 'a-id'), ('c/', 'c-id'),
323
362
('a/b', 'b-id')], tree.basis_tree())
325
364
tree.rename_one('c/foo', 'bar')
326
self.assertTreeLayout([('', root_id), ('a', 'a-id'), ('bar', 'b-id'),
327
('c', 'c-id')], tree)
328
self.assertTreeLayout([('', root_id), ('a', 'a-id'), ('c', 'c-id'),
365
self.assertTreeLayout([('', root_id), ('a/', 'a-id'), ('bar', 'b-id'),
366
('c/', 'c-id')], tree)
367
self.assertTreeLayout([('', root_id), ('a/', 'a-id'), ('c/', 'c-id'),
329
368
('a/b', 'b-id')], tree.basis_tree())
331
370
def test_rename_to_denormalised_fails(self):
337
376
self.assertRaises((errors.InvalidNormalization, UnicodeEncodeError),
338
377
tree.rename_one, 'a', u'ba\u030arry')
379
def test_rename_unversioned_non_ascii(self):
380
"""Check error when renaming an unversioned non-ascii file"""
381
self.requireFeature(features.UnicodeFilenameFeature)
382
tree = self.make_branch_and_tree(".")
383
self.build_tree([u"\xA7"])
384
e = self.assertRaises(errors.BzrRenameFailedError,
385
tree.rename_one, u"\xA7", "b")
386
self.assertIsInstance(e.extra, errors.NotVersionedError)
387
self.assertEqual(e.extra.path, u"\xA7")
389
def test_rename_into_unversioned_non_ascii_dir(self):
390
"""Check error when renaming into unversioned non-ascii directory"""
391
self.requireFeature(features.UnicodeFilenameFeature)
392
tree = self.make_branch_and_tree(".")
393
self.build_tree(["a", u"\xA7/"])
395
e = self.assertRaises(errors.BzrMoveFailedError,
396
tree.rename_one, "a", u"\xA7/a")
397
self.assertIsInstance(e.extra, errors.NotVersionedError)
398
self.assertEqual(e.extra.path, u"\xA7")
400
def test_rename_over_already_versioned_non_ascii(self):
401
"""Check error renaming over an already versioned non-ascii file"""
402
self.requireFeature(features.UnicodeFilenameFeature)
403
tree = self.make_branch_and_tree(".")
404
self.build_tree(["a", u"\xA7"])
405
tree.add(["a", u"\xA7"])
406
e = self.assertRaises(errors.BzrMoveFailedError,
407
tree.rename_one, "a", u"\xA7")
408
self.assertIsInstance(e.extra, errors.AlreadyVersionedError)
409
self.assertEqual(e.extra.path, u"\xA7")
411
def test_rename_after_non_existant_non_ascii(self):
412
"""Check error renaming after move with missing non-ascii file"""
413
self.requireFeature(features.UnicodeFilenameFeature)
414
tree = self.make_branch_and_tree(".")
415
self.build_tree(["a"])
417
e = self.assertRaises(errors.BzrMoveFailedError,
418
tree.rename_one, "a", u"\xA7", after=True)
419
self.assertIsInstance(e.extra, errors.NoSuchFile)
420
self.assertEqual(e.extra.path, u"\xA7")