/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar
1911.3.1 by John Arbash Meinel
Updated smart_add so that the AddAction can return a custom id.
1
# Copyright (C) 2005, 2006 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
from cStringIO import StringIO
1092.1.26 by Robert Collins
start writing star-topology test, realise we need smart-add change
18
import os
19
import unittest
20
1836.1.22 by John Arbash Meinel
[merge] bzr.dev 1861
21
from bzrlib import errors, ignores, osutils
1911.3.2 by John Arbash Meinel
Adding the AddFromBaseAction, which tries to reuse file ids from another tree
22
from bzrlib.add import (
23
    AddAction,
24
    AddFromBaseAction,
25
    smart_add,
26
    smart_add_tree,
27
    )
1830.3.6 by John Arbash Meinel
Test that smart_add_tree does the right thing in the presence of non-normalized filenames
28
from bzrlib.tests import TestCase, TestCaseWithTransport, TestSkipped
1765.1.1 by Robert Collins
Remove the default ignores list from bzr, lowering the minimum overhead in bzr add.
29
from bzrlib.errors import NoSuchFile
1185.53.2 by Michael Ellerman
Add tests for bzr add --dry-run
30
from bzrlib.inventory import InventoryFile, Inventory
1508.1.10 by Robert Collins
bzrlib.add.smart_add_branch is now smart_add_tree. (Robert Collins)
31
from bzrlib.workingtree import WorkingTree
1092.1.26 by Robert Collins
start writing star-topology test, realise we need smart-add change
32
1830.3.4 by John Arbash Meinel
A couple no-op cleanups
33
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
34
class TestSmartAdd(TestCaseWithTransport):
1092.1.27 by Robert Collins
two bugfixes to smart_add - do not add paths from nested trees to the parent tree, and do not mutate the user supplied file list
35
36
    def test_add_dot_from_root(self):
37
        """Test adding . from the root of the tree.""" 
38
        from bzrlib.add import smart_add
39
        paths = ("original/", "original/file1", "original/file2")
40
        self.build_tree(paths)
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
41
        wt = self.make_branch_and_tree('.')
42
        smart_add_tree(wt, (u".",))
1092.1.27 by Robert Collins
two bugfixes to smart_add - do not add paths from nested trees to the parent tree, and do not mutate the user supplied file list
43
        for path in paths:
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
44
            self.assertNotEqual(wt.path2id(path), None)
1092.1.27 by Robert Collins
two bugfixes to smart_add - do not add paths from nested trees to the parent tree, and do not mutate the user supplied file list
45
46
    def test_add_dot_from_subdir(self):
47
        """Test adding . from a subdir of the tree.""" 
48
        from bzrlib.add import smart_add
49
        paths = ("original/", "original/file1", "original/file2")
50
        self.build_tree(paths)
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
51
        wt = self.make_branch_and_tree('.')
1092.1.27 by Robert Collins
two bugfixes to smart_add - do not add paths from nested trees to the parent tree, and do not mutate the user supplied file list
52
        os.chdir("original")
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
53
        smart_add_tree(wt, (u".",))
1092.1.27 by Robert Collins
two bugfixes to smart_add - do not add paths from nested trees to the parent tree, and do not mutate the user supplied file list
54
        for path in paths:
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
55
            self.assertNotEqual(wt.path2id(path), None)
1092.1.27 by Robert Collins
two bugfixes to smart_add - do not add paths from nested trees to the parent tree, and do not mutate the user supplied file list
56
57
    def test_add_tree_from_above_tree(self):
58
        """Test adding a tree from above the tree.""" 
59
        from bzrlib.add import smart_add
60
        paths = ("original/", "original/file1", "original/file2")
1092.1.29 by Robert Collins
break smart_add into smart_add and smart_add_branch which will accept a branch parameter
61
        branch_paths = ("branch/", "branch/original/", "branch/original/file1",
62
                        "branch/original/file2")
1092.1.27 by Robert Collins
two bugfixes to smart_add - do not add paths from nested trees to the parent tree, and do not mutate the user supplied file list
63
        self.build_tree(branch_paths)
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
64
        wt = self.make_branch_and_tree('branch')
65
        smart_add_tree(wt, ("branch",))
1092.1.27 by Robert Collins
two bugfixes to smart_add - do not add paths from nested trees to the parent tree, and do not mutate the user supplied file list
66
        for path in paths:
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
67
            self.assertNotEqual(wt.path2id(path), None)
1092.1.27 by Robert Collins
two bugfixes to smart_add - do not add paths from nested trees to the parent tree, and do not mutate the user supplied file list
68
69
    def test_add_above_tree_preserves_tree(self):
70
        """Test nested trees are not affect by an add above them."""
1185.53.2 by Michael Ellerman
Add tests for bzr add --dry-run
71
        from bzrlib.add import smart_add
1092.1.27 by Robert Collins
two bugfixes to smart_add - do not add paths from nested trees to the parent tree, and do not mutate the user supplied file list
72
        paths = ("original/", "original/file1", "original/file2")
1143 by Martin Pool
- remove dead code and remove some small errors (pychecker)
73
        child_paths = ("path",)
1092.1.27 by Robert Collins
two bugfixes to smart_add - do not add paths from nested trees to the parent tree, and do not mutate the user supplied file list
74
        full_child_paths = ("original/child", "original/child/path")
75
        build_paths = ("original/", "original/file1", "original/file2", 
76
                       "original/child/", "original/child/path")
1143 by Martin Pool
- remove dead code and remove some small errors (pychecker)
77
        
1092.1.27 by Robert Collins
two bugfixes to smart_add - do not add paths from nested trees to the parent tree, and do not mutate the user supplied file list
78
        self.build_tree(build_paths)
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
79
        wt = self.make_branch_and_tree('.')
80
        child_tree = self.make_branch_and_tree('original/child')
1757.2.9 by Robert Collins
Remove spurious u cast from test_smart_add.py
81
        smart_add_tree(wt, (".",))
1092.1.27 by Robert Collins
two bugfixes to smart_add - do not add paths from nested trees to the parent tree, and do not mutate the user supplied file list
82
        for path in paths:
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
83
            self.assertNotEqual((path, wt.path2id(path)),
1092.1.27 by Robert Collins
two bugfixes to smart_add - do not add paths from nested trees to the parent tree, and do not mutate the user supplied file list
84
                                (path, None))
85
        for path in full_child_paths:
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
86
            self.assertEqual((path, wt.path2id(path)),
1092.1.27 by Robert Collins
two bugfixes to smart_add - do not add paths from nested trees to the parent tree, and do not mutate the user supplied file list
87
                             (path, None))
88
        for path in child_paths:
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
89
            self.assertEqual(child_tree.path2id(path), None)
1092.1.28 by Robert Collins
test adding lists of paths
90
91
    def test_add_paths(self):
92
        """Test smart-adding a list of paths."""
93
        from bzrlib.add import smart_add
94
        paths = ("file1", "file2")
95
        self.build_tree(paths)
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
96
        wt = self.make_branch_and_tree('.')
97
        smart_add_tree(wt, paths)
1092.1.28 by Robert Collins
test adding lists of paths
98
        for path in paths:
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
99
            self.assertNotEqual(wt.path2id(path), None)
1757.2.5 by Robert Collins
De-dup the add list so we only walk subtrees once for add.
100
    
101
    def test_add_ignored_nested_paths(self):
102
        """Test smart-adding a list of paths which includes ignored ones."""
103
        wt = self.make_branch_and_tree('.')
104
        tree_shape = ("adir/", "adir/CVS/", "adir/CVS/afile", "adir/CVS/afile2")
105
        add_paths = ("adir/CVS", "adir/CVS/afile", "adir")
106
        expected_paths = ("adir", "adir/CVS", "adir/CVS/afile", "adir/CVS/afile2")
107
        self.build_tree(tree_shape)
108
        smart_add_tree(wt, add_paths)
109
        for path in expected_paths:
110
            self.assertNotEqual(wt.path2id(path), None, "No id added for %s" % path)
1185.53.2 by Michael Ellerman
Add tests for bzr add --dry-run
111
1757.2.6 by Robert Collins
Steps towards a nicer smart add - unwind the conditional add logic - having parents not in the inventory was overly complicating the rest of the code.
112
    def test_save_false(self):
113
        """Test smart-adding a path with save set to false."""
114
        wt = self.make_branch_and_tree('.')
115
        self.build_tree(['file'])
116
        smart_add_tree(wt, ['file'], save=False)
117
        self.assertNotEqual(wt.path2id('file'), None, "No id added for 'file'")
118
        wt.read_working_inventory()
119
        self.assertEqual(wt.path2id('file'), None)
120
1185.53.2 by Michael Ellerman
Add tests for bzr add --dry-run
121
    def test_add_dry_run(self):
122
        """Test a dry run add, make sure nothing is added."""
123
        from bzrlib.commands import run_bzr
1836.1.31 by John Arbash Meinel
Make set_user_ignores a private function, and update the doc string to recommend it isn't used.
124
        ignores._set_user_ignores(['./.bazaar'])
1185.53.2 by Michael Ellerman
Add tests for bzr add --dry-run
125
        eq = self.assertEqual
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
126
        wt = self.make_branch_and_tree('.')
1185.53.2 by Michael Ellerman
Add tests for bzr add --dry-run
127
        self.build_tree(['inertiatic/', 'inertiatic/esp'])
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
128
        eq(list(wt.unknowns()), ['inertiatic'])
1185.53.2 by Michael Ellerman
Add tests for bzr add --dry-run
129
        self.capture('add --dry-run .')
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
130
        eq(list(wt.unknowns()), ['inertiatic'])
1185.53.2 by Michael Ellerman
Add tests for bzr add --dry-run
131
1185.56.2 by Michael Ellerman
Raise NoSuchFile when someone tries to add a non-existant file.
132
    def test_add_non_existant(self):
133
        """Test smart-adding a file that does not exist."""
134
        from bzrlib.add import smart_add
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
135
        wt = self.make_branch_and_tree('.')
136
        self.assertRaises(NoSuchFile, smart_add_tree, wt, 'non-existant-file')
1185.46.8 by Aaron Bentley
bzr add reports ignored patterns.
137
1765.1.1 by Robert Collins
Remove the default ignores list from bzr, lowering the minimum overhead in bzr add.
138
    def test_returns_and_ignores(self):
1185.46.8 by Aaron Bentley
bzr add reports ignored patterns.
139
        """Correctly returns added/ignored files"""
140
        from bzrlib.commands import run_bzr
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
141
        wt = self.make_branch_and_tree('.')
1836.1.15 by John Arbash Meinel
Updated WorkingTree to use the new user-level ignores.
142
        # The default ignore list includes '*.py[co]', but not CVS
1836.1.31 by John Arbash Meinel
Make set_user_ignores a private function, and update the doc string to recommend it isn't used.
143
        ignores._set_user_ignores(['./.bazaar', '*.py[co]'])
1836.1.15 by John Arbash Meinel
Updated WorkingTree to use the new user-level ignores.
144
        self.build_tree(['inertiatic/', 'inertiatic/esp', 'inertiatic/CVS',
1185.46.8 by Aaron Bentley
bzr add reports ignored patterns.
145
                        'inertiatic/foo.pyc'])
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
146
        added, ignored = smart_add_tree(wt, u'.')
1765.1.1 by Robert Collins
Remove the default ignores list from bzr, lowering the minimum overhead in bzr add.
147
        self.assertSubset(('inertiatic', 'inertiatic/esp', 'inertiatic/CVS'),
148
                          added)
1836.1.15 by John Arbash Meinel
Updated WorkingTree to use the new user-level ignores.
149
        self.assertSubset(('*.py[co]',), ignored)
150
        self.assertSubset(('inertiatic/foo.pyc',), ignored['*.py[co]'])
1185.46.8 by Aaron Bentley
bzr add reports ignored patterns.
151
152
1911.3.2 by John Arbash Meinel
Adding the AddFromBaseAction, which tries to reuse file ids from another tree
153
class AddCustomIDAction(AddAction):
1911.3.1 by John Arbash Meinel
Updated smart_add so that the AddAction can return a custom id.
154
155
    def __call__(self, inv, parent_ie, path, kind):
156
        # The first part just logs if appropriate
157
        # Now generate a custom id
158
        file_id = kind + '-' + path.raw_path.replace('/', '%')
159
        if self.should_print:
160
            self._to_file.write('added %s with id %s\n' 
161
                                % (path.raw_path, file_id))
162
        return file_id
163
164
1765.1.1 by Robert Collins
Remove the default ignores list from bzr, lowering the minimum overhead in bzr add.
165
class TestSmartAddTree(TestCaseWithTransport):
1092.1.29 by Robert Collins
break smart_add into smart_add and smart_add_branch which will accept a branch parameter
166
    """Test smart adds with a specified branch."""
167
168
    def test_add_dot_from_root(self):
169
        """Test adding . from the root of the tree.""" 
170
        paths = ("original/", "original/file1", "original/file2")
171
        self.build_tree(paths)
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
172
        wt = self.make_branch_and_tree('.')
173
        smart_add_tree(wt, (u".",))
1092.1.29 by Robert Collins
break smart_add into smart_add and smart_add_branch which will accept a branch parameter
174
        for path in paths:
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
175
            self.assertNotEqual(wt.path2id(path), None)
1092.1.29 by Robert Collins
break smart_add into smart_add and smart_add_branch which will accept a branch parameter
176
177
    def test_add_dot_from_subdir(self):
178
        """Test adding . from a subdir of the tree.""" 
179
        paths = ("original/", "original/file1", "original/file2")
180
        self.build_tree(paths)
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
181
        wt = self.make_branch_and_tree('.')
1092.1.29 by Robert Collins
break smart_add into smart_add and smart_add_branch which will accept a branch parameter
182
        os.chdir("original")
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
183
        smart_add_tree(wt, (u".",))
1092.1.29 by Robert Collins
break smart_add into smart_add and smart_add_branch which will accept a branch parameter
184
        for path in paths:
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
185
            self.assertNotEqual(wt.path2id(path), None)
1092.1.29 by Robert Collins
break smart_add into smart_add and smart_add_branch which will accept a branch parameter
186
187
    def test_add_tree_from_above_tree(self):
188
        """Test adding a tree from above the tree.""" 
189
        paths = ("original/", "original/file1", "original/file2")
190
        branch_paths = ("branch/", "branch/original/", "branch/original/file1",
191
                        "branch/original/file2")
192
        self.build_tree(branch_paths)
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
193
        tree = self.make_branch_and_tree('branch')
1508.1.10 by Robert Collins
bzrlib.add.smart_add_branch is now smart_add_tree. (Robert Collins)
194
        smart_add_tree(tree, ("branch",))
1092.1.29 by Robert Collins
break smart_add into smart_add and smart_add_branch which will accept a branch parameter
195
        for path in paths:
1508.1.10 by Robert Collins
bzrlib.add.smart_add_branch is now smart_add_tree. (Robert Collins)
196
            self.assertNotEqual(tree.path2id(path), None)
1092.1.29 by Robert Collins
break smart_add into smart_add and smart_add_branch which will accept a branch parameter
197
198
    def test_add_above_tree_preserves_tree(self):
199
        """Test nested trees are not affect by an add above them."""
200
        paths = ("original/", "original/file1", "original/file2")
201
        child_paths = ("path")
202
        full_child_paths = ("original/child", "original/child/path")
203
        build_paths = ("original/", "original/file1", "original/file2", 
204
                       "original/child/", "original/child/path")
205
        self.build_tree(build_paths)
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
206
        tree = self.make_branch_and_tree('.')
207
        child_tree = self.make_branch_and_tree("original/child")
1185.33.66 by Martin Pool
[patch] use unicode literals for all hardcoded paths (Alexander Belchenko)
208
        smart_add_tree(tree, (u".",))
1092.1.29 by Robert Collins
break smart_add into smart_add and smart_add_branch which will accept a branch parameter
209
        for path in paths:
1508.1.10 by Robert Collins
bzrlib.add.smart_add_branch is now smart_add_tree. (Robert Collins)
210
            self.assertNotEqual((path, tree.path2id(path)),
1092.1.29 by Robert Collins
break smart_add into smart_add and smart_add_branch which will accept a branch parameter
211
                                (path, None))
212
        for path in full_child_paths:
1508.1.10 by Robert Collins
bzrlib.add.smart_add_branch is now smart_add_tree. (Robert Collins)
213
            self.assertEqual((path, tree.path2id(path)),
1092.1.29 by Robert Collins
break smart_add into smart_add and smart_add_branch which will accept a branch parameter
214
                             (path, None))
215
        for path in child_paths:
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
216
            self.assertEqual(child_tree.path2id(path), None)
1092.1.29 by Robert Collins
break smart_add into smart_add and smart_add_branch which will accept a branch parameter
217
218
    def test_add_paths(self):
219
        """Test smart-adding a list of paths."""
220
        paths = ("file1", "file2")
221
        self.build_tree(paths)
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
222
        wt = self.make_branch_and_tree('.')
223
        smart_add_tree(wt, paths)
1092.1.29 by Robert Collins
break smart_add into smart_add and smart_add_branch which will accept a branch parameter
224
        for path in paths:
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
225
            self.assertNotEqual(wt.path2id(path), None)
226
1850.2.1 by John Arbash Meinel
Fix bug #52578, smart-add wasn't recursing all supplied directories.
227
    def test_add_multiple_dirs(self):
228
        """Test smart adding multiple directories at once."""
229
        added_paths = ['file1', 'file2',
230
                       'dir1/', 'dir1/file3',
231
                       'dir1/subdir2/', 'dir1/subdir2/file4',
232
                       'dir2/', 'dir2/file5',
233
                      ]
234
        not_added = ['file6', 'dir3/', 'dir3/file7', 'dir3/file8']
235
        self.build_tree(added_paths)
236
        self.build_tree(not_added)
237
238
        wt = self.make_branch_and_tree('.')
239
        smart_add_tree(wt, ['file1', 'file2', 'dir1', 'dir2'])
240
241
        for path in added_paths:
242
            self.assertNotEqual(None, wt.path2id(path.rstrip('/')),
243
                    'Failed to add path: %s' % (path,))
244
        for path in not_added:
245
            self.assertEqual(None, wt.path2id(path.rstrip('/')),
246
                    'Accidentally added path: %s' % (path,))
247
1911.3.1 by John Arbash Meinel
Updated smart_add so that the AddAction can return a custom id.
248
    def test_custom_ids(self):
249
        sio = StringIO()
1911.3.2 by John Arbash Meinel
Adding the AddFromBaseAction, which tries to reuse file ids from another tree
250
        action = AddCustomIDAction(to_file=sio, should_print=True)
1911.3.1 by John Arbash Meinel
Updated smart_add so that the AddAction can return a custom id.
251
        self.build_tree(['file1', 'dir1/', 'dir1/file2'])
252
253
        wt = self.make_branch_and_tree('.')
254
        smart_add_tree(wt, ['.'], action=action)
1911.3.5 by John Arbash Meinel
There is no strict ordering file addition, other than directories are added before child files
255
        # The order of adds is not strictly fixed:
256
        sio.seek(0)
257
        lines = sorted(sio.readlines())
258
        self.assertEqualDiff(['added dir1 with id directory-dir1\n',
259
                              'added dir1/file2 with id file-dir1%file2\n',
260
                              'added file1 with id file-file1\n',
261
                             ], lines)
1911.3.1 by John Arbash Meinel
Updated smart_add so that the AddAction can return a custom id.
262
        self.assertEqual([('', wt.inventory.root.file_id),
263
                          ('dir1', 'directory-dir1'),
264
                          ('dir1/file2', 'file-dir1%file2'),
265
                          ('file1', 'file-file1'),
266
                         ], [(path, ie.file_id) for path, ie
267
                                in wt.inventory.iter_entries()])
268
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
269
1911.3.2 by John Arbash Meinel
Adding the AddFromBaseAction, which tries to reuse file ids from another tree
270
class TestAddFrom(TestCaseWithTransport):
271
    """Tests for AddFromBaseAction"""
272
273
    def make_base_tree(self):
274
        self.base_tree = self.make_branch_and_tree('base')
275
        self.build_tree(['base/a', 'base/b',
276
                         'base/dir/', 'base/dir/a',
277
                         'base/dir/subdir/',
278
                         'base/dir/subdir/b',
279
                        ])
280
        self.base_tree.add(['a', 'b', 'dir', 'dir/a',
281
                            'dir/subdir', 'dir/subdir/b'])
282
        self.base_tree.commit('creating initial tree.')
283
284
    def add_helper(self, base_tree, base_path, new_tree, file_list,
285
                   should_print=False):
286
        to_file = StringIO()
287
        base_tree.lock_read()
288
        try:
289
            new_tree.lock_write()
290
            try:
291
                action = AddFromBaseAction(base_tree, base_path,
292
                                           to_file=to_file,
293
                                           should_print=should_print)
294
                smart_add_tree(new_tree, file_list, action=action)
295
            finally:
296
                new_tree.unlock()
297
        finally:
298
            base_tree.unlock()
299
        return to_file.getvalue()
300
301
    def test_copy_all(self):
302
        self.make_base_tree()
303
        new_tree = self.make_branch_and_tree('new')
304
        files = ['a', 'b',
305
                 'dir/', 'dir/a',
306
                 'dir/subdir/',
307
                 'dir/subdir/b',
308
                ]
309
        self.build_tree(['new/' + fn for fn in files])
310
        self.add_helper(self.base_tree, '', new_tree, ['new'])
311
312
        for fn in files:
313
            base_file_id = self.base_tree.path2id(fn)
314
            new_file_id = new_tree.path2id(fn)
315
            self.assertEqual(base_file_id, new_file_id)
316
317
    def test_copy_from_dir(self):
318
        self.make_base_tree()
319
        new_tree = self.make_branch_and_tree('new')
320
321
        self.build_tree(['new/a', 'new/b', 'new/c',
322
                         'new/subdir/', 'new/subdir/b', 'new/subdir/d'])
323
        self.add_helper(self.base_tree, 'dir', new_tree, ['new'])
324
325
        # We 'a' and 'b' exist in the root, and they are being added
326
        # in a new 'root'. Since ROOT ids are not unique, we will
327
        # use those ids
328
        # TODO: This will probably change once trees have a unique root id
329
        # It is definitely arguable that 'a' should get the id of
330
        # 'dir/a' not of 'a'.
331
        self.assertEqual(self.base_tree.path2id('a'),
332
                         new_tree.path2id('a'))
333
        self.assertEqual(self.base_tree.path2id('b'),
334
                         new_tree.path2id('b'))
335
336
        # Because we specified 'dir/' as the base path, and we have
337
        # nothing named 'subdir' in the base tree, we should grab the
338
        # ids from there
339
        self.assertEqual(self.base_tree.path2id('dir/subdir'),
340
                         new_tree.path2id('subdir'))
341
        self.assertEqual(self.base_tree.path2id('dir/subdir/b'),
342
                         new_tree.path2id('subdir/b'))
343
344
        # These should get newly generated ids
345
        c_id = new_tree.path2id('c')
346
        self.assertNotEqual(None, c_id)
347
        self.failIf(c_id in self.base_tree)
348
349
        d_id = new_tree.path2id('subdir/d')
350
        self.assertNotEqual(None, d_id)
351
        self.failIf(d_id in self.base_tree)
352
353
    def test_copy_existing_dir(self):
354
        self.make_base_tree()
355
        new_tree = self.make_branch_and_tree('new')
356
        self.build_tree(['new/subby/', 'new/subby/a', 'new/subby/b'])
357
358
        subdir_file_id = self.base_tree.path2id('dir/subdir')
359
        new_tree.add(['subby'], [subdir_file_id])
360
        self.add_helper(self.base_tree, '', new_tree, ['new'])
361
        # Because 'subby' already points to subdir, we should add
362
        # 'b' with the same id
363
        self.assertEqual(self.base_tree.path2id('dir/subdir/b'),
364
                         new_tree.path2id('subby/b'))
365
366
        # 'subby/a' should be added with a new id because there is no
367
        # matching path or child of 'subby'.
368
        a_id = new_tree.path2id('subby/a')
369
        self.assertNotEqual(None, a_id)
370
        self.failIf(a_id in self.base_tree)
371
372
1830.3.6 by John Arbash Meinel
Test that smart_add_tree does the right thing in the presence of non-normalized filenames
373
class TestAddNonNormalized(TestCaseWithTransport):
374
375
    def make(self):
376
        try:
377
            self.build_tree([u'a\u030a'])
378
        except UnicodeError:
379
            raise TestSkipped('Filesystem cannot create unicode filenames')
380
381
        self.wt = self.make_branch_and_tree('.')
382
383
    def test_accessible_explicit(self):
384
        self.make()
385
        orig = osutils.normalized_filename
386
        osutils.normalized_filename = osutils._accessible_normalized_filename
387
        try:
388
            smart_add_tree(self.wt, [u'a\u030a'])
1907.1.3 by Aaron Bentley
Fixed unicode test cases
389
            self.assertEqual([('', 'directory'), (u'\xe5', 'file')],
1830.3.17 by John Arbash Meinel
list_files() with wrong normalized_filename code raises exceptions. Fix this
390
                    [(path, ie.kind) for path,ie in 
391
                        self.wt.inventory.iter_entries()])
1830.3.6 by John Arbash Meinel
Test that smart_add_tree does the right thing in the presence of non-normalized filenames
392
        finally:
393
            osutils.normalized_filename = orig
394
395
    def test_accessible_implicit(self):
396
        self.make()
397
        orig = osutils.normalized_filename
398
        osutils.normalized_filename = osutils._accessible_normalized_filename
399
        try:
400
            smart_add_tree(self.wt, [])
1907.1.3 by Aaron Bentley
Fixed unicode test cases
401
            self.assertEqual([('', 'directory'), (u'\xe5', 'file')],
1830.3.17 by John Arbash Meinel
list_files() with wrong normalized_filename code raises exceptions. Fix this
402
                    [(path, ie.kind) for path,ie in 
403
                        self.wt.inventory.iter_entries()])
1830.3.6 by John Arbash Meinel
Test that smart_add_tree does the right thing in the presence of non-normalized filenames
404
        finally:
405
            osutils.normalized_filename = orig
406
407
    def test_inaccessible_explicit(self):
408
        self.make()
409
        orig = osutils.normalized_filename
410
        osutils.normalized_filename = osutils._inaccessible_normalized_filename
411
        try:
412
            self.assertRaises(errors.InvalidNormalization,
413
                    smart_add_tree, self.wt, [u'a\u030a'])
414
        finally:
415
            osutils.normalized_filename = orig
416
417
    def test_inaccessible_implicit(self):
418
        self.make()
419
        orig = osutils.normalized_filename
420
        osutils.normalized_filename = osutils._inaccessible_normalized_filename
421
        try:
422
            # TODO: jam 20060701 In the future, this should probably
423
            #       just ignore files that don't fit the normalization
424
            #       rules, rather than exploding
425
            self.assertRaises(errors.InvalidNormalization,
426
                    smart_add_tree, self.wt, [])
427
        finally:
428
            osutils.normalized_filename = orig
429
430
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
431
class TestAddActions(TestCase):
1185.53.2 by Michael Ellerman
Add tests for bzr add --dry-run
432
1757.2.6 by Robert Collins
Steps towards a nicer smart add - unwind the conditional add logic - having parents not in the inventory was overly complicating the rest of the code.
433
    def test_quiet(self):
434
        self.run_action("")
435
436
    def test__print(self):
437
        self.run_action("added path\n")
438
439
    def run_action(self, output):
1757.2.3 by Robert Collins
Get add tests passing.
440
        from bzrlib.add import AddAction, FastPath
1185.53.2 by Michael Ellerman
Add tests for bzr add --dry-run
441
        inv = Inventory()
1092.1.30 by Robert Collins
change smart_add reporting of added files to callback with the entry, and change the inventory.add signature to return the added entry
442
        stdout = StringIO()
1757.2.6 by Robert Collins
Steps towards a nicer smart add - unwind the conditional add logic - having parents not in the inventory was overly complicating the rest of the code.
443
        action = AddAction(to_file=stdout, should_print=bool(output))
1185.53.2 by Michael Ellerman
Add tests for bzr add --dry-run
444
1757.2.3 by Robert Collins
Get add tests passing.
445
        self.apply_redirected(None, stdout, None, action, inv, None, FastPath('path'), 'file')
1185.53.2 by Michael Ellerman
Add tests for bzr add --dry-run
446
        self.assertEqual(stdout.getvalue(), output)