1
# Copyright (C) 2007 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17
"""Tests for WorkingTree.paths2ids.
19
This API probably needs to be exposed as a tree implementation test, but these
20
initial tests are for the specific cases being refactored from
21
find_ids_across_trees.
24
from operator import attrgetter
26
from bzrlib import errors
27
from bzrlib.tests.workingtree_implementations import TestCaseWithWorkingTree
30
# TODO: This needs an additional test: do a merge, then do a
31
# paths2id(trees=left parent only), and also with (trees=all parents) to check
32
# that only the requested trees are considered - i.e. have an unversioned path
33
# in the unlisted tree, or an extra file that moves into the selected path but
34
# should not be returned
36
# TODO: test that supplying paths with duplication - i.e. foo, foo, foo/bar -
37
# does not result in garbage out.
39
# TODO: Are we meant to raise the precise unversioned paths when some are
40
# unversioned - if so, test this.
42
class TestPaths2Ids(TestCaseWithWorkingTree):
44
def assertExpectedIds(self, ids, tree, paths, trees=None,
45
require_versioned=True):
46
"""Run paths2ids for tree, and check the result."""
49
map(apply, map(attrgetter('lock_read'), trees))
50
result = tree.paths2ids(paths, trees,
51
require_versioned=require_versioned)
52
map(apply, map(attrgetter('unlock'), trees))
54
result = tree.paths2ids(paths,
55
require_versioned=require_versioned)
56
self.assertEqual(set(ids), result)
59
def test_paths_none_result_none(self):
60
tree = self.make_branch_and_tree('tree')
62
self.assertEqual(None, tree.paths2ids(None))
65
def test_find_single_root(self):
66
tree = self.make_branch_and_tree('tree')
67
self.assertExpectedIds([tree.path2id('')], tree, [''])
69
def test_find_tree_and_clone_roots(self):
70
tree = self.make_branch_and_tree('tree')
71
clone = tree.bzrdir.clone('clone').open_workingtree()
72
clone.lock_tree_write()
73
clone_root_id = 'new-id'
74
clone.set_root_id(clone_root_id)
75
tree_root_id = tree.path2id('')
77
self.assertExpectedIds([tree_root_id, clone_root_id], tree, [''], [clone])
79
def test_find_tree_basis_roots(self):
80
tree = self.make_branch_and_tree('tree')
82
basis = tree.basis_tree()
83
basis_root_id = basis.path2id('')
84
tree.lock_tree_write()
85
tree_root_id = 'new-id'
86
tree.set_root_id(tree_root_id)
88
self.assertExpectedIds([tree_root_id, basis_root_id], tree, [''], [basis])
90
def test_find_children_of_moved_directories(self):
91
"""Check the basic nasty corner case that path2ids should handle.
93
This is the following situation:
97
/dir/child-moves child-moves
98
/dir/child-stays child-stays
99
/dir/child-goes child-goes
103
/child-moves child-moves
106
/newdir/dir/child-stays child-stays
107
/newdir/dir/new-child new-child
109
In english: we move a directory under a directory that was a sibling,
110
and at the same time remove, or move out of the directory, some of its
111
children, and give it a new child previous absent or a sibling.
113
current_tree.path2ids(['newdir'], [basis]) is meant to handle this
114
correctly: that is it should return the ids:
115
newdir because it was provided
116
dir, because its under newdir in current
117
child-moves because its under dir in old
118
child-stays either because its under newdir/dir in current, or under dir in old
119
child-goes because its under dir in old.
120
new-child because its under dir in new
122
Symmetrically, current_tree.path2ids(['dir'], [basis]) is meant to show
123
new-child, even though its not under the path 'dir' in current, because
124
its under a path selected by 'dir' in basis:
125
dir because its selected in basis.
126
child-moves because its under dir in old
127
child-stays either because its under newdir/dir in current, or under dir in old
128
child-goes because its under dir in old.
129
new-child because its under dir in new.
131
tree = self.make_branch_and_tree('tree')
133
['tree/dir/', 'tree/dir/child-moves', 'tree/dir/child-stays',
134
'tree/dir/child-goes'])
135
tree.add(['dir', 'dir/child-moves', 'dir/child-stays', 'dir/child-goes'],
136
['dir', 'child-moves', 'child-stays', 'child-goes'])
137
tree.commit('create basis')
138
basis = tree.basis_tree()
139
tree.unversion(['child-goes'])
140
tree.rename_one('dir/child-moves', 'child-moves')
141
self.build_tree(['tree/newdir/'])
142
tree.add(['newdir'], ['newdir'])
143
tree.rename_one('dir/child-stays', 'child-stays')
144
tree.rename_one('dir', 'newdir/dir')
145
tree.rename_one('child-stays', 'newdir/dir/child-stays')
146
self.build_tree(['tree/newdir/dir/new-child'])
147
tree.add(['newdir/dir/new-child'], ['new-child'])
148
self.assertExpectedIds(
149
['newdir', 'dir', 'child-moves', 'child-stays', 'child-goes',
150
'new-child'], tree, ['newdir'], [basis])
151
self.assertExpectedIds(
152
['dir', 'child-moves', 'child-stays', 'child-goes', 'new-child'],
153
tree, ['dir'], [basis])
155
def test_unversioned_one_tree(self):
156
tree = self.make_branch_and_tree('tree')
157
self.build_tree(['tree/unversioned'])
158
self.assertExpectedIds([], tree, ['unversioned'], require_versioned=False)
160
self.assertRaises(errors.PathsNotVersionedError, tree.paths2ids, ['unversioned'])
163
def test_unversioned_in_one_of_multiple_trees(self):
164
# in this test, the path is unversioned in only one tree, and thus
165
# should not raise an error: it must be unversioned in *all* trees to
167
tree = self.make_branch_and_tree('tree')
168
tree.commit('make basis')
169
basis = tree.basis_tree()
170
self.build_tree(['tree/in-one'])
171
tree.add(['in-one'], ['in-one'])
172
self.assertExpectedIds(['in-one'], tree, ['in-one'], [basis])
174
def test_unversioned_all_of_multiple_trees(self):
175
# in this test, the path is unversioned in every tree, and thus
176
# should not raise an error: it must be unversioned in *all* trees to
178
tree = self.make_branch_and_tree('tree')
179
tree.commit('make basis')
180
basis = tree.basis_tree()
181
self.assertExpectedIds([], tree, ['unversioned'], [basis],
182
require_versioned=False)
185
self.assertRaises(errors.PathsNotVersionedError, tree.paths2ids,
186
['unversioned'], [basis])
187
self.assertRaises(errors.PathsNotVersionedError, basis.paths2ids,
188
['unversioned'], [tree])