~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

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

  • Committer: Robert Collins
  • Date: 2007-03-08 04:06:06 UTC
  • mfrom: (2323.1.1 integration)
  • mto: This revision was merged to the branch mainline in revision 2442.
  • Revision ID: robertc@robertcollins.net-20070308040606-84gsniv56huiyjt4
Merge bzr.dev.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# Copyright (C) 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 WorkingTree.paths2ids.
 
18
 
 
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.
 
22
"""
 
23
 
 
24
from operator import attrgetter
 
25
 
 
26
from bzrlib import errors
 
27
from bzrlib.tests.workingtree_implementations import TestCaseWithWorkingTree
 
28
 
 
29
 
 
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
 
35
 
 
36
# TODO: test that supplying paths with duplication - i.e. foo, foo, foo/bar -
 
37
# does not result in garbage out.
 
38
 
 
39
# TODO: Are we meant to raise the precise unversioned paths when some are
 
40
# unversioned - if so, test this.
 
41
 
 
42
class TestPaths2Ids(TestCaseWithWorkingTree):
 
43
 
 
44
    def assertExpectedIds(self, ids, tree, paths, trees=None,
 
45
        require_versioned=True):
 
46
        """Run paths2ids for tree, and check the result."""
 
47
        tree.lock_read()
 
48
        if trees:
 
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))
 
53
        else:
 
54
            result = tree.paths2ids(paths,
 
55
                require_versioned=require_versioned)
 
56
        self.assertEqual(set(ids), result)
 
57
        tree.unlock()
 
58
 
 
59
    def test_paths_none_result_none(self):
 
60
        tree = self.make_branch_and_tree('tree')
 
61
        tree.lock_read()
 
62
        self.assertEqual(None, tree.paths2ids(None))
 
63
        tree.unlock()
 
64
 
 
65
    def test_find_single_root(self):
 
66
        tree = self.make_branch_and_tree('tree')
 
67
        self.assertExpectedIds([tree.path2id('')], tree, [''])
 
68
 
 
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('')
 
76
        clone.unlock()
 
77
        self.assertExpectedIds([tree_root_id, clone_root_id], tree, [''], [clone])
 
78
 
 
79
    def test_find_tree_basis_roots(self):
 
80
        tree = self.make_branch_and_tree('tree')
 
81
        tree.commit('basis')
 
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)
 
87
        tree.unlock()
 
88
        self.assertExpectedIds([tree_root_id, basis_root_id], tree, [''], [basis])
 
89
 
 
90
    def test_find_children_of_moved_directories(self):
 
91
        """Check the basic nasty corner case that path2ids should handle.
 
92
 
 
93
        This is the following situation:
 
94
        basis: 
 
95
          / ROOT
 
96
          /dir dir
 
97
          /dir/child-moves child-moves
 
98
          /dir/child-stays child-stays
 
99
          /dir/child-goes  child-goes
 
100
 
 
101
        current tree:
 
102
          / ROOT
 
103
          /child-moves child-moves
 
104
          /newdir newdir
 
105
          /newdir/dir  dir
 
106
          /newdir/dir/child-stays child-stays
 
107
          /newdir/dir/new-child   new-child
 
108
 
 
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.
 
112
 
 
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
 
121
        
 
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.
 
130
        """
 
131
        tree = self.make_branch_and_tree('tree')
 
132
        self.build_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])
 
154
 
 
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)
 
159
        tree.lock_read()
 
160
        self.assertRaises(errors.PathsNotVersionedError, tree.paths2ids, ['unversioned'])
 
161
        tree.unlock()
 
162
 
 
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
 
166
        # error.
 
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])
 
173
 
 
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
 
177
        # error.
 
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)
 
183
        tree.lock_read()
 
184
        basis.lock_read()
 
185
        self.assertRaises(errors.PathsNotVersionedError, tree.paths2ids,
 
186
            ['unversioned'], [basis])
 
187
        self.assertRaises(errors.PathsNotVersionedError, basis.paths2ids,
 
188
            ['unversioned'], [tree])
 
189
        basis.unlock()
 
190
        tree.unlock()