1
# Copyright (C) 2006 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17
"""Tests of the WorkingTree.unversion API."""
23
from bzrlib.tests.per_workingtree import TestCaseWithWorkingTree
26
class TestUnversion(TestCaseWithWorkingTree):
28
def test_unversion_requires_write_lock(self):
29
"""WT.unversion([]) in a read lock raises ReadOnlyError."""
30
tree = self.make_branch_and_tree('.')
32
self.assertRaises(errors.ReadOnlyError, tree.unversion, [])
35
def test_unversion_missing_file(self):
36
"""WT.unversion(['missing-id']) raises NoSuchId."""
37
tree = self.make_branch_and_tree('.')
38
self.assertRaises(errors.NoSuchId, tree.unversion, ['missing-id'])
40
def test_unversion_parent_and_child_renamed_bug_187207(self):
41
# When unversioning dirstate trees show a bug in dealing with
42
# unversioning children of reparented children of unversioned
43
# paths when relocation entries are present and the relocation
44
# points later into the dirstate.
45
tree = self.make_branch_and_tree(['.'])
46
self.build_tree(['del/', 'del/sub/', 'del/sub/b'])
47
tree.add(['del', 'del/sub', 'del/sub/b'], ['del', 'sub', 'b'])
49
tree.rename_one('del/sub', 'sub')
50
self.assertEqual('sub/b', tree.id2path('b'))
51
tree.unversion(['del', 'b'])
52
self.assertRaises(errors.NoSuchId, tree.id2path, 'b')
54
def test_unversion_several_files(self):
55
"""After unversioning several files, they should not be versioned."""
56
tree = self.make_branch_and_tree('.')
57
self.build_tree(['a', 'b', 'c'])
58
tree.add(['a', 'b', 'c'], ['a-id', 'b-id', 'c-id'])
59
# within a lock unversion should take effect
61
tree.unversion(['a-id', 'b-id'])
62
self.assertFalse(tree.has_id('a-id'))
63
self.assertFalse(tree.has_id('b-id'))
64
self.assertTrue(tree.has_id('c-id'))
65
self.assertTrue(tree.has_filename('a'))
66
self.assertTrue(tree.has_filename('b'))
67
self.assertTrue(tree.has_filename('c'))
69
# the changes should have persisted to disk - reopen the workingtree
71
tree = tree.bzrdir.open_workingtree()
73
self.assertFalse(tree.has_id('a-id'))
74
self.assertFalse(tree.has_id('b-id'))
75
self.assertTrue(tree.has_id('c-id'))
76
self.assertTrue(tree.has_filename('a'))
77
self.assertTrue(tree.has_filename('b'))
78
self.assertTrue(tree.has_filename('c'))
81
def test_unversion_subtree(self):
82
"""Unversioning the root of a subtree unversions the entire subtree."""
83
tree = self.make_branch_and_tree('.')
84
self.build_tree(['a/', 'a/b', 'c'])
85
tree.add(['a', 'a/b', 'c'], ['a-id', 'b-id', 'c-id'])
86
# within a lock unversion should take effect
88
tree.unversion(['a-id'])
89
self.assertFalse(tree.has_id('a-id'))
90
self.assertFalse(tree.has_id('b-id'))
91
self.assertTrue(tree.has_id('c-id'))
92
self.assertTrue(tree.has_filename('a'))
93
self.assertTrue(tree.has_filename('a/b'))
94
self.assertTrue(tree.has_filename('c'))
97
def test_unversion_subtree_and_children(self):
98
"""Passing a child id will raise NoSuchId.
100
This is because the parent directory will have already been removed.
102
tree = self.make_branch_and_tree('.')
103
self.build_tree(['a/', 'a/b', 'a/c', 'd'])
104
tree.add(['a', 'a/b', 'a/c', 'd'], ['a-id', 'b-id', 'c-id', 'd-id'])
107
tree.unversion(['b-id', 'a-id'])
108
self.assertFalse(tree.has_id('a-id'))
109
self.assertFalse(tree.has_id('b-id'))
110
self.assertFalse(tree.has_id('c-id'))
111
self.assertTrue(tree.has_id('d-id'))
112
# The files are still on disk
113
self.assertTrue(tree.has_filename('a'))
114
self.assertTrue(tree.has_filename('a/b'))
115
self.assertTrue(tree.has_filename('a/c'))
116
self.assertTrue(tree.has_filename('d'))
120
def test_unversion_renamed(self):
121
tree = self.make_branch_and_tree('a')
122
self.build_tree(['a/dir/', 'a/dir/f1', 'a/dir/f2', 'a/dir/f3',
124
tree.add(['dir', 'dir/f1', 'dir/f2', 'dir/f3', 'dir2'],
125
['dir-id', 'f1-id', 'f2-id', 'f3-id', 'dir2-id'])
126
rev_id1 = tree.commit('init')
127
# Start off by renaming entries, and then unversion a bunch of entries
128
# https://bugs.launchpad.net/bzr/+bug/114615
129
tree.rename_one('dir/f1', 'dir/a')
130
tree.rename_one('dir/f2', 'dir/z')
131
tree.move(['dir/f3'], 'dir2')
135
root_id = tree.get_root_id()
136
paths = [(path, ie.file_id)
137
for path, ie in tree.iter_entries_by_dir()]
140
self.assertEqual([('', root_id),
145
('dir2/f3', 'f3-id'),
148
tree.unversion(set(['dir-id']))
149
paths = [(path, ie.file_id)
150
for path, ie in tree.iter_entries_by_dir()]
152
self.assertEqual([('', root_id),
154
('dir2/f3', 'f3-id'),
157
def test_unversion_after_conflicted_merge(self):
158
# Test for bug #114615
159
tree_a = self.make_branch_and_tree('A')
160
self.build_tree(['A/a/', 'A/a/m', 'A/a/n'])
161
tree_a.add(['a', 'a/m', 'a/n'], ['a-id', 'm-id', 'n-id'])
162
tree_a.commit('init')
166
root_id = tree_a.get_root_id()
170
tree_b = tree_a.bzrdir.sprout('B').open_workingtree()
171
self.build_tree(['B/xyz/'])
172
tree_b.add(['xyz'], ['xyz-id'])
173
tree_b.rename_one('a/m', 'xyz/m')
174
tree_b.unversion(['a-id'])
175
tree_b.commit('delete in B')
177
paths = [(path, ie.file_id)
178
for path, ie in tree_b.iter_entries_by_dir()]
179
self.assertEqual([('', root_id),
184
self.build_tree_contents([('A/a/n', 'new contents for n\n')])
185
tree_a.commit('change n in A')
187
# Merging from A should introduce conflicts because 'n' was modified
188
# and removed, so 'a' needs to be restored. We also have a conflict
189
# because 'a' is still an existing directory
190
num_conflicts = tree_b.merge_from_branch(tree_a.branch)
191
self.assertEqual(4, num_conflicts)
192
paths = [(path, ie.file_id)
193
for path, ie in tree_b.iter_entries_by_dir()]
194
self.assertEqual([('', root_id),
197
('a/n.OTHER', 'n-id'),
200
tree_b.unversion(['a-id'])
201
paths = [(path, ie.file_id)
202
for path, ie in tree_b.iter_entries_by_dir()]
203
self.assertEqual([('', root_id),