~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

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

  • Committer: Aaron Bentley
  • Date: 2008-10-16 21:27:10 UTC
  • mfrom: (0.15.26 unshelve)
  • mto: (0.16.74 shelf-ui)
  • mto: This revision was merged to the branch mainline in revision 3820.
  • Revision ID: aaron@aaronbentley.com-20081016212710-h9av3nhk76dvmsv5
Merge with unshelve

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# Copyright (C) 2006, 2007, 2008 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.remove'"""
 
18
 
 
19
from bzrlib.tests.workingtree_implementations import TestCaseWithWorkingTree
 
20
from bzrlib import errors, ignores, osutils
 
21
 
 
22
class TestRemove(TestCaseWithWorkingTree):
 
23
    """Tests WorkingTree.remove"""
 
24
 
 
25
    files = ['a', 'b/', 'b/c', 'd/']
 
26
    rfiles = ['b/c', 'b', 'a', 'd']
 
27
 
 
28
    def get_tree(self, files):
 
29
        tree = self.make_branch_and_tree('.')
 
30
        self.build_tree(files)
 
31
        self.failUnlessExists(files)
 
32
        return tree
 
33
 
 
34
    def get_committed_tree(self, files, message="Committing"):
 
35
        tree = self.get_tree(files)
 
36
        tree.add(files)
 
37
        tree.commit(message)
 
38
        self.assertInWorkingTree(files)
 
39
        return tree
 
40
 
 
41
    def assertRemovedAndDeleted(self, files):
 
42
        self.assertNotInWorkingTree(files)
 
43
        self.failIfExists(files)
 
44
 
 
45
    def assertRemovedAndNotDeleted(self, files):
 
46
        self.assertNotInWorkingTree(files)
 
47
        self.failUnlessExists(files)
 
48
 
 
49
    def test_remove_keep(self):
 
50
        """Check that files and directories are unversioned but not deleted."""
 
51
        tree = self.get_tree(TestRemove.files)
 
52
        tree.add(TestRemove.files)
 
53
        self.assertInWorkingTree(TestRemove.files)
 
54
 
 
55
        tree.remove(TestRemove.files)
 
56
        self.assertRemovedAndNotDeleted(TestRemove.files)
 
57
 
 
58
    def test_remove_keep_subtree(self):
 
59
        """Check that a directory is unversioned but not deleted."""
 
60
        tree = self.make_branch_and_tree('.')
 
61
        subtree = self.make_branch_and_tree('subtree')
 
62
        tree.add('subtree', 'subtree-id')
 
63
 
 
64
        tree.remove('subtree')
 
65
        self.assertRemovedAndNotDeleted('subtree')
 
66
 
 
67
    def test_remove_unchanged_files(self):
 
68
        """Check that unchanged files are removed and deleted."""
 
69
        tree = self.get_committed_tree(TestRemove.files)
 
70
        tree.remove(TestRemove.files, keep_files=False)
 
71
        self.assertRemovedAndDeleted(TestRemove.files)
 
72
        tree._validate()
 
73
 
 
74
    def test_remove_added_files(self):
 
75
        """Removal of newly added files must fail."""
 
76
        tree = self.get_tree(TestRemove.files)
 
77
        tree.add(TestRemove.files)
 
78
        self.assertInWorkingTree(TestRemove.files)
 
79
        err = self.assertRaises(errors.BzrRemoveChangedFilesError, tree.remove,
 
80
            TestRemove.files, keep_files=False)
 
81
        self.assertContainsRe(err.changes_as_text,
 
82
            '(?s)added:.*a.*b/.*b/c.*d/')
 
83
        self.assertInWorkingTree(TestRemove.files)
 
84
        self.failUnlessExists(TestRemove.files)
 
85
        tree._validate()
 
86
 
 
87
    def test_remove_changed_file(self):
 
88
        """Removal of a changed files must fail."""
 
89
        tree = self.get_committed_tree(['a'])
 
90
        self.build_tree_contents([('a', "some other new content!")])
 
91
        self.assertInWorkingTree('a')
 
92
        err = self.assertRaises(errors.BzrRemoveChangedFilesError, tree.remove,
 
93
            'a', keep_files=False)
 
94
        self.assertContainsRe(err.changes_as_text, '(?s)modified:.*a')
 
95
        self.assertInWorkingTree('a')
 
96
        self.failUnlessExists('a')
 
97
        tree._validate()
 
98
 
 
99
    def test_remove_deleted_files(self):
 
100
        """Check that files are removed if they don't exist any more."""
 
101
        tree = self.get_committed_tree(TestRemove.files)
 
102
        for f in TestRemove.rfiles:
 
103
            osutils.delete_any(f)
 
104
        self.assertInWorkingTree(TestRemove.files)
 
105
        self.failIfExists(TestRemove.files)
 
106
        tree.remove(TestRemove.files, keep_files=False)
 
107
        self.assertRemovedAndDeleted(TestRemove.files)
 
108
        tree._validate()
 
109
 
 
110
    def test_remove_renamed_files(self):
 
111
        """Check that files are removed even if they are renamed."""
 
112
        tree = self.get_committed_tree(TestRemove.files)
 
113
 
 
114
        for f in TestRemove.rfiles:
 
115
            tree.rename_one(f,f+'x')
 
116
        rfilesx = ['bx/cx', 'bx', 'ax', 'dx']
 
117
        self.assertInWorkingTree(rfilesx)
 
118
        self.failUnlessExists(rfilesx)
 
119
 
 
120
        tree.remove(rfilesx, keep_files=False)
 
121
        self.assertRemovedAndDeleted(rfilesx)
 
122
        tree._validate()
 
123
 
 
124
    def test_remove_renamed_changed_files(self):
 
125
        """Check that files are not removed if they are renamed and changed."""
 
126
        tree = self.get_committed_tree(TestRemove.files)
 
127
 
 
128
        for f in TestRemove.rfiles:
 
129
            tree.rename_one(f,f+'x')
 
130
        rfilesx = ['bx/cx', 'bx', 'ax', 'dx']
 
131
        self.build_tree_contents([('ax','changed and renamed!'),
 
132
                                  ('bx/cx','changed and renamed!')])
 
133
        self.assertInWorkingTree(rfilesx)
 
134
        self.failUnlessExists(rfilesx)
 
135
 
 
136
        err = self.assertRaises(errors.BzrRemoveChangedFilesError, tree.remove,
 
137
            rfilesx, keep_files=False)
 
138
        self.assertContainsRe(err.changes_as_text,
 
139
            '(?s)modified:.*ax.*bx/cx')
 
140
        self.assertInWorkingTree(rfilesx)
 
141
        self.failUnlessExists(rfilesx)
 
142
        tree._validate()
 
143
 
 
144
    def test_force_remove_changed_files(self):
 
145
        """Check that changed files are removed and deleted when forced."""
 
146
        tree = self.get_tree(TestRemove.files)
 
147
        tree.add(TestRemove.files)
 
148
        self.assertInWorkingTree(TestRemove.files)
 
149
 
 
150
        tree.remove(TestRemove.files, keep_files=False, force=True)
 
151
        self.assertRemovedAndDeleted(TestRemove.files)
 
152
        tree._validate()
 
153
 
 
154
    def test_remove_unknown_files(self):
 
155
        """Try to delete unknown files."""
 
156
        tree = self.get_tree(TestRemove.files)
 
157
        err = self.assertRaises(errors.BzrRemoveChangedFilesError, tree.remove,
 
158
            TestRemove.files, keep_files=False)
 
159
        self.assertContainsRe(err.changes_as_text,
 
160
            '(?s)unknown:.*d/.*b/c.*b/.*a.*')
 
161
        tree._validate()
 
162
 
 
163
    def test_remove_nonexisting_files(self):
 
164
        """Try to delete non-existing files."""
 
165
        tree = self.get_tree(TestRemove.files)
 
166
        tree.remove([''], keep_files=False)
 
167
        tree.remove(['xyz', 'abc/def'], keep_files=False)
 
168
        tree._validate()
 
169
 
 
170
    def test_remove_unchanged_directory(self):
 
171
        """Unchanged directories should be deleted."""
 
172
        files = ['b/', 'b/c', 'b/sub_directory/', 'b/sub_directory/with_file']
 
173
        tree = self.get_committed_tree(files)
 
174
        tree.remove('b', keep_files=False)
 
175
        self.assertRemovedAndDeleted('b')
 
176
        tree._validate()
 
177
 
 
178
    def test_remove_absent_directory(self):
 
179
        """Removing a absent directory succeeds without corruption (#150438)."""
 
180
        paths = ['a/', 'a/b']
 
181
        tree = self.get_committed_tree(paths)
 
182
        self.get_transport('.').delete_tree('a')
 
183
        tree.remove(['a'])
 
184
        self.assertRemovedAndDeleted('b')
 
185
        tree._validate()
 
186
 
 
187
    def test_remove_unknown_ignored_files(self):
 
188
        """Unknown ignored files should be deleted."""
 
189
        tree = self.get_committed_tree(['b/'])
 
190
        ignores.add_runtime_ignores(["*ignored*"])
 
191
 
 
192
        self.build_tree(['unknown_ignored_file'])
 
193
        self.assertNotEquals(None, tree.is_ignored('unknown_ignored_file'))
 
194
        tree.remove('unknown_ignored_file', keep_files=False)
 
195
        self.assertRemovedAndDeleted('unknown_ignored_file')
 
196
 
 
197
        self.build_tree(['b/unknown_ignored_file', 'b/unknown_ignored_dir/'])
 
198
        self.assertNotEquals(None, tree.is_ignored('b/unknown_ignored_file'))
 
199
        self.assertNotEquals(None, tree.is_ignored('b/unknown_ignored_dir'))
 
200
        tree.remove('b', keep_files=False)
 
201
        self.assertRemovedAndDeleted('b')
 
202
        tree._validate()
 
203
 
 
204
    def test_remove_changed_ignored_files(self):
 
205
        """Changed ignored files should not be deleted."""
 
206
        files = ['an_ignored_file']
 
207
        tree = self.get_tree(files)
 
208
        tree.add(files)
 
209
        ignores.add_runtime_ignores(["*ignored*"])
 
210
        self.assertInWorkingTree(files)
 
211
        self.assertNotEquals(None, tree.is_ignored(files[0]))
 
212
        err = self.assertRaises(errors.BzrRemoveChangedFilesError, tree.remove,
 
213
            files, keep_files=False)
 
214
        self.assertContainsRe(err.changes_as_text,
 
215
            '(?s)added:.*' + files[0])
 
216
        self.assertInWorkingTree(files)
 
217
        tree._validate()
 
218
 
 
219
    def test_dont_remove_directory_with_unknowns(self):
 
220
        """Directories with unknowns should not be deleted."""
 
221
        directories = ['a/', 'b/', 'c/', 'c/c/']
 
222
        tree = self.get_committed_tree(directories)
 
223
 
 
224
        self.build_tree(['a/unknown_file'])
 
225
        err = self.assertRaises(errors.BzrRemoveChangedFilesError, tree.remove,
 
226
            'a', keep_files=False)
 
227
        self.assertContainsRe(err.changes_as_text,
 
228
            '(?s)unknown:.*a/unknown_file')
 
229
 
 
230
        self.build_tree(['b/unknown_directory'])
 
231
        err = self.assertRaises(errors.BzrRemoveChangedFilesError, tree.remove,
 
232
            'b', keep_files=False)
 
233
        self.assertContainsRe(err.changes_as_text,
 
234
            '(?s)unknown:.*b/unknown_directory')
 
235
 
 
236
        self.build_tree(['c/c/unknown_file'])
 
237
        err = self.assertRaises(errors.BzrRemoveChangedFilesError, tree.remove,
 
238
            'c/c', keep_files=False)
 
239
        self.assertContainsRe(err.changes_as_text,
 
240
            '(?s)unknown:.*c/c/unknown_file')
 
241
 
 
242
        self.assertInWorkingTree(directories)
 
243
        self.failUnlessExists(directories)
 
244
        tree._validate()
 
245
 
 
246
    def test_force_remove_directory_with_unknowns(self):
 
247
        """Unchanged non-empty directories should be deleted when forced."""
 
248
        files = ['b/', 'b/c']
 
249
        tree = self.get_committed_tree(files)
 
250
 
 
251
        other_files = ['b/unknown_file', 'b/sub_directory/',
 
252
            'b/sub_directory/with_file', 'b/sub_directory/sub_directory/']
 
253
        self.build_tree(other_files)
 
254
 
 
255
        self.assertInWorkingTree(files)
 
256
        self.failUnlessExists(files)
 
257
 
 
258
        tree.remove('b', keep_files=False, force=True)
 
259
 
 
260
        self.assertRemovedAndDeleted(files)
 
261
        self.assertRemovedAndDeleted(other_files)
 
262
        tree._validate()
 
263
 
 
264
    def test_remove_directory_with_changed_file(self):
 
265
        """Refuse to delete directories with changed files."""
 
266
        files = ['b/', 'b/c']
 
267
        tree = self.get_committed_tree(files)
 
268
        self.build_tree_contents([('b/c', "some other new content!")])
 
269
 
 
270
        err = self.assertRaises(errors.BzrRemoveChangedFilesError, tree.remove,
 
271
            'b', keep_files=False)
 
272
        self.assertContainsRe(err.changes_as_text, '(?s)modified:.*b/c')
 
273
        self.assertInWorkingTree(files)
 
274
        self.failUnlessExists(files)
 
275
 
 
276
        # see if we can force it now..
 
277
        tree.remove('b', keep_files=False, force=True)
 
278
        self.assertRemovedAndDeleted(files)
 
279
        tree._validate()
 
280
 
 
281
    def test_remove_directory_with_renames(self):
 
282
        """Delete directory with renames in or out."""
 
283
 
 
284
        files = ['a/', 'a/file', 'a/directory/', 'b/']
 
285
        files_to_move = ['a/file', 'a/directory/']
 
286
 
 
287
        tree = self.get_committed_tree(files)
 
288
        # move stuff from a=>b
 
289
        tree.move(['a/file', 'a/directory'], to_dir='b')
 
290
 
 
291
        moved_files = ['b/file', 'b/directory/']
 
292
        self.assertRemovedAndDeleted(files_to_move)
 
293
        self.assertInWorkingTree(moved_files)
 
294
        self.failUnlessExists(moved_files)
 
295
 
 
296
        # check if it works with renames out
 
297
        tree.remove('a', keep_files=False)
 
298
        self.assertRemovedAndDeleted(['a/'])
 
299
 
 
300
        # check if it works with renames in
 
301
        tree.remove('b', keep_files=False)
 
302
        self.assertRemovedAndDeleted(['b/'])
 
303
        tree._validate()
 
304
 
 
305
    def test_non_cwd(self):
 
306
        tree = self.make_branch_and_tree('tree')
 
307
        self.build_tree(['tree/dir/', 'tree/dir/file'])
 
308
        tree.add(['dir', 'dir/file'])
 
309
        tree.commit('add file')
 
310
        tree.remove('dir/', keep_files=False)
 
311
        self.failIfExists('tree/dir/file')
 
312
        self.assertNotInWorkingTree('tree/dir/file', 'tree')
 
313
        tree._validate()
 
314
 
 
315
    def test_remove_uncommitted_removed_file(self):
 
316
        # As per bug #152811
 
317
        tree = self.get_committed_tree(['a'])
 
318
        tree.remove('a', keep_files=False)
 
319
        tree.remove('a', keep_files=False)
 
320
        self.failIfExists('a')
 
321
        tree._validate()
 
322
 
 
323
    def test_remove_file_and_containing_dir(self):
 
324
        tree = self.get_committed_tree(['config/', 'config/file'])
 
325
        tree.remove('config/file', keep_files=False)
 
326
        tree.remove('config', keep_files=False)
 
327
        self.failIfExists('config/file')
 
328
        self.failIfExists('config')
 
329
        tree._validate()
 
330
 
 
331
    def test_remove_dir_before_bzr(self):
 
332
        # As per bug #272648. Note that a file must be present in the directory
 
333
        # or the bug doesn't manifest itself.
 
334
        tree = self.get_committed_tree(['.aaa/', '.aaa/file'])
 
335
        tree.remove('.aaa/', keep_files=False)
 
336
        self.failIfExists('.aaa/file')
 
337
        self.failIfExists('.aaa')
 
338
        tree._validate()