/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar

« back to all changes in this revision

Viewing changes to bzrlib/tests/test_smart_add.py

  • Committer: v.ladeuil+lp at free
  • Date: 2006-10-12 14:29:32 UTC
  • mto: (2145.1.1 keepalive)
  • mto: This revision was merged to the branch mainline in revision 2146.
  • Revision ID: v.ladeuil+lp@free.fr-20061012142932-7221fe16d2b48fa3
Shuffle http related test code. Hopefully it ends up at the right place :)

* bzrlib/tests/HttpServer.py: 
New file. bzrlib.tests.ChrootedTestCase use HttpServer. So the
class can't be defined in bzrlib.tests.HTTPUtils because it
creates a circular dependency (bzrlib.tests.HTTPUtils needs to
import bzrlib.tests).

* bzrlib/transport/http/_urllib.py: 
Transfer test server definition to bzrlib.tests.HttpServer. Clean
up imports.

* bzrlib/transport/http/_pycurl.py: 
Transfer test server definition to bzrlib.tests.HttpServer. Clean
up imports.

* bzrlib/transport/http/__init__.py: 
Transfer all test related code to either bzrlib.tests.HttpServer
and bzrlib.tests.HTTPUtils.
Fix all use of TransportNotPossible and InvalidURL by prefixing it
by 'errors.' (this seems to be the preferred way in the rest of
bzr).
Get rid of unused imports.

* bzrlib/tests/test_transport.py:
(ReadonlyDecoratorTransportTest.test_local_parameters,
FakeNFSDecoratorTests.test_http_parameters): Use HttpServer from
bzrlib.tests.HttpServer instead of bzrlib.transport.http.

* bzrlib/tests/test_sftp_transport.py:
(set_test_transport_to_sftp): Use HttpServer from
bzrlib.tests.HttpServer instead of bzrlib.transport.http.

* bzrlib/tests/test_selftest.py:
(TestTestCaseWithTransport.test_get_readonly_url_http): Use
HttpServer from bzrlib.tests.HttpServer instead of
bzrlib.transport.http.

* bzrlib/tests/test_repository.py: 
Does *not* use HttpServer.

* bzrlib/tests/test_http.py: 
Build on top of bzrlib.tests.HttpServer and bzrlib.tests.HTTPUtils
instead of bzrlib.transport.http.

* bzrlib/tests/test_bzrdir.py:
(ChrootedTests.setUp): Use HttpServer from bzrlib.tests.HttpServer
instead of bzrlib.transport.http.

* bzrlib/tests/branch_implementations/test_http.py:
(HTTPBranchTests.setUp): Use HttpServer from bzrlib.tests.HttpServer
instead of bzrlib.transport.http.

* bzrlib/tests/branch_implementations/test_branch.py:
(ChrootedTests.setUp): Use HttpServer from bzrlib.tests.HttpServer
instead of bzrlib.transport.http.

* bzrlib/tests/__init__.py:
(ChrootedTestCase.setUp): Use HttpServer from
bzrlib.tests.HttpServer instead of bzrlib.transport.http.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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
 
18
import os
 
19
import unittest
 
20
 
 
21
from bzrlib import errors, ignores, osutils
 
22
from bzrlib.add import (
 
23
    AddAction,
 
24
    AddFromBaseAction,
 
25
    smart_add,
 
26
    smart_add_tree,
 
27
    )
 
28
from bzrlib.tests import TestCase, TestCaseWithTransport, TestSkipped
 
29
from bzrlib.errors import NoSuchFile
 
30
from bzrlib.inventory import InventoryFile, Inventory
 
31
from bzrlib.workingtree import WorkingTree
 
32
 
 
33
 
 
34
class TestSmartAdd(TestCaseWithTransport):
 
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)
 
41
        wt = self.make_branch_and_tree('.')
 
42
        smart_add_tree(wt, (u".",))
 
43
        for path in paths:
 
44
            self.assertNotEqual(wt.path2id(path), None)
 
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)
 
51
        wt = self.make_branch_and_tree('.')
 
52
        os.chdir("original")
 
53
        smart_add_tree(wt, (u".",))
 
54
        for path in paths:
 
55
            self.assertNotEqual(wt.path2id(path), None)
 
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")
 
61
        branch_paths = ("branch/", "branch/original/", "branch/original/file1",
 
62
                        "branch/original/file2")
 
63
        self.build_tree(branch_paths)
 
64
        wt = self.make_branch_and_tree('branch')
 
65
        smart_add_tree(wt, ("branch",))
 
66
        for path in paths:
 
67
            self.assertNotEqual(wt.path2id(path), None)
 
68
 
 
69
    def test_add_above_tree_preserves_tree(self):
 
70
        """Test nested trees are not affect by an add above them."""
 
71
        from bzrlib.add import smart_add
 
72
        paths = ("original/", "original/file1", "original/file2")
 
73
        child_paths = ("path",)
 
74
        full_child_paths = ("original/child", "original/child/path")
 
75
        build_paths = ("original/", "original/file1", "original/file2", 
 
76
                       "original/child/", "original/child/path")
 
77
        
 
78
        self.build_tree(build_paths)
 
79
        wt = self.make_branch_and_tree('.')
 
80
        child_tree = self.make_branch_and_tree('original/child')
 
81
        smart_add_tree(wt, (".",))
 
82
        for path in paths:
 
83
            self.assertNotEqual((path, wt.path2id(path)),
 
84
                                (path, None))
 
85
        for path in full_child_paths:
 
86
            self.assertEqual((path, wt.path2id(path)),
 
87
                             (path, None))
 
88
        for path in child_paths:
 
89
            self.assertEqual(child_tree.path2id(path), None)
 
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)
 
96
        wt = self.make_branch_and_tree('.')
 
97
        smart_add_tree(wt, paths)
 
98
        for path in paths:
 
99
            self.assertNotEqual(wt.path2id(path), None)
 
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)
 
111
 
 
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
 
 
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
 
124
        eq = self.assertEqual
 
125
        wt = self.make_branch_and_tree('.')
 
126
        self.build_tree(['inertiatic/', 'inertiatic/esp'])
 
127
        eq(list(wt.unknowns()), ['inertiatic'])
 
128
        self.capture('add --dry-run .')
 
129
        eq(list(wt.unknowns()), ['inertiatic'])
 
130
 
 
131
    def test_add_non_existant(self):
 
132
        """Test smart-adding a file that does not exist."""
 
133
        from bzrlib.add import smart_add
 
134
        wt = self.make_branch_and_tree('.')
 
135
        self.assertRaises(NoSuchFile, smart_add_tree, wt, 'non-existant-file')
 
136
 
 
137
    def test_returns_and_ignores(self):
 
138
        """Correctly returns added/ignored files"""
 
139
        from bzrlib.commands import run_bzr
 
140
        wt = self.make_branch_and_tree('.')
 
141
        # The default ignore list includes '*.py[co]', but not CVS
 
142
        ignores._set_user_ignores(['*.py[co]'])
 
143
        self.build_tree(['inertiatic/', 'inertiatic/esp', 'inertiatic/CVS',
 
144
                        'inertiatic/foo.pyc'])
 
145
        added, ignored = smart_add_tree(wt, u'.')
 
146
        self.assertSubset(('inertiatic', 'inertiatic/esp', 'inertiatic/CVS'),
 
147
                          added)
 
148
        self.assertSubset(('*.py[co]',), ignored)
 
149
        self.assertSubset(('inertiatic/foo.pyc',), ignored['*.py[co]'])
 
150
 
 
151
 
 
152
class AddCustomIDAction(AddAction):
 
153
 
 
154
    def __call__(self, inv, parent_ie, path, kind):
 
155
        # The first part just logs if appropriate
 
156
        # Now generate a custom id
 
157
        file_id = kind + '-' + path.raw_path.replace('/', '%')
 
158
        if self.should_print:
 
159
            self._to_file.write('added %s with id %s\n' 
 
160
                                % (path.raw_path, file_id))
 
161
        return file_id
 
162
 
 
163
 
 
164
class TestSmartAddTree(TestCaseWithTransport):
 
165
    """Test smart adds with a specified branch."""
 
166
 
 
167
    def test_add_dot_from_root(self):
 
168
        """Test adding . from the root of the tree.""" 
 
169
        paths = ("original/", "original/file1", "original/file2")
 
170
        self.build_tree(paths)
 
171
        wt = self.make_branch_and_tree('.')
 
172
        smart_add_tree(wt, (u".",))
 
173
        for path in paths:
 
174
            self.assertNotEqual(wt.path2id(path), None)
 
175
 
 
176
    def test_add_dot_from_subdir(self):
 
177
        """Test adding . from a subdir of the tree.""" 
 
178
        paths = ("original/", "original/file1", "original/file2")
 
179
        self.build_tree(paths)
 
180
        wt = self.make_branch_and_tree('.')
 
181
        os.chdir("original")
 
182
        smart_add_tree(wt, (u".",))
 
183
        for path in paths:
 
184
            self.assertNotEqual(wt.path2id(path), None)
 
185
 
 
186
    def test_add_tree_from_above_tree(self):
 
187
        """Test adding a tree from above the tree.""" 
 
188
        paths = ("original/", "original/file1", "original/file2")
 
189
        branch_paths = ("branch/", "branch/original/", "branch/original/file1",
 
190
                        "branch/original/file2")
 
191
        self.build_tree(branch_paths)
 
192
        tree = self.make_branch_and_tree('branch')
 
193
        smart_add_tree(tree, ("branch",))
 
194
        for path in paths:
 
195
            self.assertNotEqual(tree.path2id(path), None)
 
196
 
 
197
    def test_add_above_tree_preserves_tree(self):
 
198
        """Test nested trees are not affect by an add above them."""
 
199
        paths = ("original/", "original/file1", "original/file2")
 
200
        child_paths = ("path")
 
201
        full_child_paths = ("original/child", "original/child/path")
 
202
        build_paths = ("original/", "original/file1", "original/file2", 
 
203
                       "original/child/", "original/child/path")
 
204
        self.build_tree(build_paths)
 
205
        tree = self.make_branch_and_tree('.')
 
206
        child_tree = self.make_branch_and_tree("original/child")
 
207
        smart_add_tree(tree, (u".",))
 
208
        for path in paths:
 
209
            self.assertNotEqual((path, tree.path2id(path)),
 
210
                                (path, None))
 
211
        for path in full_child_paths:
 
212
            self.assertEqual((path, tree.path2id(path)),
 
213
                             (path, None))
 
214
        for path in child_paths:
 
215
            self.assertEqual(child_tree.path2id(path), None)
 
216
 
 
217
    def test_add_paths(self):
 
218
        """Test smart-adding a list of paths."""
 
219
        paths = ("file1", "file2")
 
220
        self.build_tree(paths)
 
221
        wt = self.make_branch_and_tree('.')
 
222
        smart_add_tree(wt, paths)
 
223
        for path in paths:
 
224
            self.assertNotEqual(wt.path2id(path), None)
 
225
 
 
226
    def test_add_multiple_dirs(self):
 
227
        """Test smart adding multiple directories at once."""
 
228
        added_paths = ['file1', 'file2',
 
229
                       'dir1/', 'dir1/file3',
 
230
                       'dir1/subdir2/', 'dir1/subdir2/file4',
 
231
                       'dir2/', 'dir2/file5',
 
232
                      ]
 
233
        not_added = ['file6', 'dir3/', 'dir3/file7', 'dir3/file8']
 
234
        self.build_tree(added_paths)
 
235
        self.build_tree(not_added)
 
236
 
 
237
        wt = self.make_branch_and_tree('.')
 
238
        smart_add_tree(wt, ['file1', 'file2', 'dir1', 'dir2'])
 
239
 
 
240
        for path in added_paths:
 
241
            self.assertNotEqual(None, wt.path2id(path.rstrip('/')),
 
242
                    'Failed to add path: %s' % (path,))
 
243
        for path in not_added:
 
244
            self.assertEqual(None, wt.path2id(path.rstrip('/')),
 
245
                    'Accidentally added path: %s' % (path,))
 
246
 
 
247
    def test_custom_ids(self):
 
248
        sio = StringIO()
 
249
        action = AddCustomIDAction(to_file=sio, should_print=True)
 
250
        self.build_tree(['file1', 'dir1/', 'dir1/file2'])
 
251
 
 
252
        wt = self.make_branch_and_tree('.')
 
253
        smart_add_tree(wt, ['.'], action=action)
 
254
        # The order of adds is not strictly fixed:
 
255
        sio.seek(0)
 
256
        lines = sorted(sio.readlines())
 
257
        self.assertEqualDiff(['added dir1 with id directory-dir1\n',
 
258
                              'added dir1/file2 with id file-dir1%file2\n',
 
259
                              'added file1 with id file-file1\n',
 
260
                             ], lines)
 
261
        self.assertEqual([('', wt.inventory.root.file_id),
 
262
                          ('dir1', 'directory-dir1'),
 
263
                          ('dir1/file2', 'file-dir1%file2'),
 
264
                          ('file1', 'file-file1'),
 
265
                         ], [(path, ie.file_id) for path, ie
 
266
                                in wt.inventory.iter_entries()])
 
267
 
 
268
 
 
269
class TestAddFrom(TestCaseWithTransport):
 
270
    """Tests for AddFromBaseAction"""
 
271
 
 
272
    def make_base_tree(self):
 
273
        self.base_tree = self.make_branch_and_tree('base')
 
274
        self.build_tree(['base/a', 'base/b',
 
275
                         'base/dir/', 'base/dir/a',
 
276
                         'base/dir/subdir/',
 
277
                         'base/dir/subdir/b',
 
278
                        ])
 
279
        self.base_tree.add(['a', 'b', 'dir', 'dir/a',
 
280
                            'dir/subdir', 'dir/subdir/b'])
 
281
        self.base_tree.commit('creating initial tree.')
 
282
 
 
283
    def add_helper(self, base_tree, base_path, new_tree, file_list,
 
284
                   should_print=False):
 
285
        to_file = StringIO()
 
286
        base_tree.lock_read()
 
287
        try:
 
288
            new_tree.lock_write()
 
289
            try:
 
290
                action = AddFromBaseAction(base_tree, base_path,
 
291
                                           to_file=to_file,
 
292
                                           should_print=should_print)
 
293
                smart_add_tree(new_tree, file_list, action=action)
 
294
            finally:
 
295
                new_tree.unlock()
 
296
        finally:
 
297
            base_tree.unlock()
 
298
        return to_file.getvalue()
 
299
 
 
300
    def test_copy_all(self):
 
301
        self.make_base_tree()
 
302
        new_tree = self.make_branch_and_tree('new')
 
303
        files = ['a', 'b',
 
304
                 'dir/', 'dir/a',
 
305
                 'dir/subdir/',
 
306
                 'dir/subdir/b',
 
307
                ]
 
308
        self.build_tree(['new/' + fn for fn in files])
 
309
        self.add_helper(self.base_tree, '', new_tree, ['new'])
 
310
 
 
311
        for fn in files:
 
312
            base_file_id = self.base_tree.path2id(fn)
 
313
            new_file_id = new_tree.path2id(fn)
 
314
            self.assertEqual(base_file_id, new_file_id)
 
315
 
 
316
    def test_copy_from_dir(self):
 
317
        self.make_base_tree()
 
318
        new_tree = self.make_branch_and_tree('new')
 
319
 
 
320
        self.build_tree(['new/a', 'new/b', 'new/c',
 
321
                         'new/subdir/', 'new/subdir/b', 'new/subdir/d'])
 
322
        self.add_helper(self.base_tree, 'dir', new_tree, ['new'])
 
323
 
 
324
        # We 'a' and 'b' exist in the root, and they are being added
 
325
        # in a new 'root'. Since ROOT ids are not unique, we will
 
326
        # use those ids
 
327
        # TODO: This will probably change once trees have a unique root id
 
328
        # It is definitely arguable that 'a' should get the id of
 
329
        # 'dir/a' not of 'a'.
 
330
        self.assertEqual(self.base_tree.path2id('a'),
 
331
                         new_tree.path2id('a'))
 
332
        self.assertEqual(self.base_tree.path2id('b'),
 
333
                         new_tree.path2id('b'))
 
334
 
 
335
        # Because we specified 'dir/' as the base path, and we have
 
336
        # nothing named 'subdir' in the base tree, we should grab the
 
337
        # ids from there
 
338
        self.assertEqual(self.base_tree.path2id('dir/subdir'),
 
339
                         new_tree.path2id('subdir'))
 
340
        self.assertEqual(self.base_tree.path2id('dir/subdir/b'),
 
341
                         new_tree.path2id('subdir/b'))
 
342
 
 
343
        # These should get newly generated ids
 
344
        c_id = new_tree.path2id('c')
 
345
        self.assertNotEqual(None, c_id)
 
346
        self.failIf(c_id in self.base_tree)
 
347
 
 
348
        d_id = new_tree.path2id('subdir/d')
 
349
        self.assertNotEqual(None, d_id)
 
350
        self.failIf(d_id in self.base_tree)
 
351
 
 
352
    def test_copy_existing_dir(self):
 
353
        self.make_base_tree()
 
354
        new_tree = self.make_branch_and_tree('new')
 
355
        self.build_tree(['new/subby/', 'new/subby/a', 'new/subby/b'])
 
356
 
 
357
        subdir_file_id = self.base_tree.path2id('dir/subdir')
 
358
        new_tree.add(['subby'], [subdir_file_id])
 
359
        self.add_helper(self.base_tree, '', new_tree, ['new'])
 
360
        # Because 'subby' already points to subdir, we should add
 
361
        # 'b' with the same id
 
362
        self.assertEqual(self.base_tree.path2id('dir/subdir/b'),
 
363
                         new_tree.path2id('subby/b'))
 
364
 
 
365
        # 'subby/a' should be added with a new id because there is no
 
366
        # matching path or child of 'subby'.
 
367
        a_id = new_tree.path2id('subby/a')
 
368
        self.assertNotEqual(None, a_id)
 
369
        self.failIf(a_id in self.base_tree)
 
370
 
 
371
 
 
372
class TestAddNonNormalized(TestCaseWithTransport):
 
373
 
 
374
    def make(self):
 
375
        try:
 
376
            self.build_tree([u'a\u030a'])
 
377
        except UnicodeError:
 
378
            raise TestSkipped('Filesystem cannot create unicode filenames')
 
379
 
 
380
        self.wt = self.make_branch_and_tree('.')
 
381
 
 
382
    def test_accessible_explicit(self):
 
383
        self.make()
 
384
        orig = osutils.normalized_filename
 
385
        osutils.normalized_filename = osutils._accessible_normalized_filename
 
386
        try:
 
387
            smart_add_tree(self.wt, [u'a\u030a'])
 
388
            self.assertEqual([('', 'directory'), (u'\xe5', 'file')],
 
389
                    [(path, ie.kind) for path,ie in 
 
390
                        self.wt.inventory.iter_entries()])
 
391
        finally:
 
392
            osutils.normalized_filename = orig
 
393
 
 
394
    def test_accessible_implicit(self):
 
395
        self.make()
 
396
        orig = osutils.normalized_filename
 
397
        osutils.normalized_filename = osutils._accessible_normalized_filename
 
398
        try:
 
399
            smart_add_tree(self.wt, [])
 
400
            self.assertEqual([('', 'directory'), (u'\xe5', 'file')],
 
401
                    [(path, ie.kind) for path,ie in 
 
402
                        self.wt.inventory.iter_entries()])
 
403
        finally:
 
404
            osutils.normalized_filename = orig
 
405
 
 
406
    def test_inaccessible_explicit(self):
 
407
        self.make()
 
408
        orig = osutils.normalized_filename
 
409
        osutils.normalized_filename = osutils._inaccessible_normalized_filename
 
410
        try:
 
411
            self.assertRaises(errors.InvalidNormalization,
 
412
                    smart_add_tree, self.wt, [u'a\u030a'])
 
413
        finally:
 
414
            osutils.normalized_filename = orig
 
415
 
 
416
    def test_inaccessible_implicit(self):
 
417
        self.make()
 
418
        orig = osutils.normalized_filename
 
419
        osutils.normalized_filename = osutils._inaccessible_normalized_filename
 
420
        try:
 
421
            # TODO: jam 20060701 In the future, this should probably
 
422
            #       just ignore files that don't fit the normalization
 
423
            #       rules, rather than exploding
 
424
            self.assertRaises(errors.InvalidNormalization,
 
425
                    smart_add_tree, self.wt, [])
 
426
        finally:
 
427
            osutils.normalized_filename = orig
 
428
 
 
429
 
 
430
class TestAddActions(TestCase):
 
431
 
 
432
    def test_quiet(self):
 
433
        self.run_action("")
 
434
 
 
435
    def test__print(self):
 
436
        self.run_action("added path\n")
 
437
 
 
438
    def run_action(self, output):
 
439
        from bzrlib.add import AddAction, FastPath
 
440
        inv = Inventory()
 
441
        stdout = StringIO()
 
442
        action = AddAction(to_file=stdout, should_print=bool(output))
 
443
 
 
444
        self.apply_redirected(None, stdout, None, action, inv, None, FastPath('path'), 'file')
 
445
        self.assertEqual(stdout.getvalue(), output)