~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/workingtree_implementations/test_move.py

  • Committer: Robert Collins
  • Date: 2007-03-07 08:02:58 UTC
  • mfrom: (2255.2.239 dirstate)
  • mto: This revision was merged to the branch mainline in revision 2322.
  • Revision ID: robertc@robertcollins.net-20070307080258-fi172acyjga89fz5
(robertc) Merge dirstate and subtrees. (Robert Collins, Martin Pool, Aaaron Bentley, John A Meinel, James Westby)

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# Copyright (C) 2006, 2007 Canonical Ltd
 
2
#
 
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.
 
7
#
 
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.
 
12
#
 
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
 
16
 
 
17
"""Tests for interface conformance of 'WorkingTree.move'"""
 
18
 
 
19
import os
 
20
 
 
21
from bzrlib import (
 
22
    errors,
 
23
    osutils,
 
24
    )
 
25
 
 
26
from bzrlib.workingtree_4 import WorkingTreeFormat4
 
27
from bzrlib.tests.workingtree_implementations import TestCaseWithWorkingTree
 
28
 
 
29
 
 
30
class TestMove(TestCaseWithWorkingTree):
 
31
 
 
32
    def get_tree_layout(self, tree):
 
33
        """Get the (path, file_id) pairs for the current tree."""
 
34
        tree.lock_read()
 
35
        try:
 
36
            return [(path, ie.file_id) for path, ie
 
37
                    in tree.iter_entries_by_dir()]
 
38
        finally:
 
39
            tree.unlock()
 
40
 
 
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)
 
45
 
 
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
 
50
        """
 
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))
 
57
 
 
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
 
62
        """
 
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))
 
69
 
 
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
 
74
        """
 
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',
 
81
                          after=False)
 
82
 
 
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
 
87
        """
 
88
        self.build_tree(['a1', 'sub1/'])
 
89
        tree = self.make_branch_and_tree('.')
 
90
        tree.add(['a1', 'sub1'])
 
91
        tree.commit('initial commit')
 
92
 
 
93
        try:
 
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',
 
97
                                after=False)
 
98
        except TypeError:
 
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):
 
102
                raise
 
103
 
 
104
    def test_move_target_not_dir(self):
 
105
        tree = self.make_branch_and_tree('.')
 
106
        self.build_tree(['a'])
 
107
        tree.add(['a'])
 
108
        tree.commit('initial', rev_id='rev-1')
 
109
 
 
110
        self.assertRaises(errors.BzrMoveFailedError,
 
111
                          tree.move, ['a'], 'not-a-dir')
 
112
 
 
113
    def test_move_non_existent(self):
 
114
        tree = self.make_branch_and_tree('.')
 
115
        self.build_tree(['a/'])
 
116
        tree.add(['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'], '')
 
122
 
 
123
    def test_move_target_not_versioned(self):
 
124
        tree = self.make_branch_and_tree('.')
 
125
        self.build_tree(['a/', 'b'])
 
126
        tree.add(['b'])
 
127
        tree.commit('initial', rev_id='rev-1')
 
128
        self.assertRaises(errors.BzrMoveFailedError,
 
129
                          tree.move, ['b'], 'a')
 
130
 
 
131
    def test_move_unversioned(self):
 
132
        tree = self.make_branch_and_tree('.')
 
133
        self.build_tree(['a/', 'b'])
 
134
        tree.add(['a'])
 
135
        tree.commit('initial', rev_id='rev-1')
 
136
        self.assertRaises(errors.BzrMoveFailedError,
 
137
                          tree.move, ['b'], 'a')
 
138
 
 
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)
 
155
        else:
 
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())
 
160
 
 
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')
 
180
 
 
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')
 
196
 
 
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)
 
211
        else:
 
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())
 
217
 
 
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')
 
223
 
 
224
        self.assertRaises(errors.BzrMoveFailedError,
 
225
                          tree.move, ['b/a'], 'b')
 
226
 
 
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')
 
232
 
 
233
        self.assertRaises(errors.BzrMoveFailedError,
 
234
                          tree.move, ['a'], 'a')
 
235
 
 
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')
 
243
 
 
244
        self.assertTreeLayout([('', root_id), ('a', 'a-id'), ('b', 'b-id')],
 
245
                              tree)
 
246
        # We don't need after=True as long as source is missing and target
 
247
        # exists.
 
248
        self.assertEqual([('a', 'b/a')],
 
249
            tree.move(['a'], 'b'))
 
250
        self.assertTreeLayout([('', root_id), ('b', 'b-id'), ('b/a', 'a-id')],
 
251
                              tree)
 
252
        self.assertTreeLayout([('', root_id), ('a', 'a-id'), ('b', 'b-id')],
 
253
                              tree.basis_tree())
 
254
 
 
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')
 
262
 
 
263
        self.assertTreeLayout([('', root_id), ('a', 'a-id'), ('b', 'b-id')],
 
264
                              tree)
 
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')],
 
269
                              tree)
 
270
        self.assertTreeLayout([('', root_id), ('a', 'a-id'), ('b', 'b-id')],
 
271
                              tree.basis_tree())
 
272
 
 
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()
 
279
 
 
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')],
 
284
                              tree.basis_tree())
 
285
 
 
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()
 
292
 
 
293
        # TODO: jam 20070225 I would usually use 'rb', but assertFileEqual
 
294
        #       uses 'r'.
 
295
        a_file = open('a', 'r')
 
296
        try:
 
297
            a_text = a_file.read()
 
298
        finally:
 
299
            a_file.close()
 
300
        ba_file = open('b/a', 'r')
 
301
        try:
 
302
            ba_text = ba_file.read()
 
303
        finally:
 
304
            ba_file.close()
 
305
 
 
306
        self.assertTreeLayout([('', root_id), ('a', 'a-id'), ('b', 'b-id')],
 
307
                              tree)
 
308
        self.assertRaises(errors.RenameFailedFilesExist,
 
309
                          tree.move, ['a'], 'b', after=False)
 
310
        self.assertTreeLayout([('', root_id), ('a', 'a-id'), ('b', 'b-id')],
 
311
                              tree)
 
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')],
 
318
                              tree)
 
319
        self.assertTreeLayout([('', root_id), ('a', 'a-id'), ('b', 'b-id')],
 
320
                              tree.basis_tree())
 
321
        # But it shouldn't actually move anything
 
322
        self.assertFileEqual(a_text, 'a')
 
323
        self.assertFileEqual(ba_text, 'b/a')
 
324
 
 
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()
 
332
 
 
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())
 
341
 
 
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()
 
349
 
 
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())
 
356
 
 
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())