~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

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

  • Committer: John Arbash Meinel
  • Author(s): Mark Hammond
  • Date: 2008-09-09 17:02:21 UTC
  • mto: This revision was merged to the branch mainline in revision 3697.
  • Revision ID: john@arbash-meinel.com-20080909170221-svim3jw2mrz0amp3
An updated transparent icon for bzr.

Show diffs side-by-side

added added

removed removed

Lines of Context:
12
12
#
13
13
# You should have received a copy of the GNU General Public License
14
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
 
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
16
16
 
17
17
"""Tests of the parent related functions of WorkingTrees."""
18
18
 
19
 
from cStringIO import StringIO
 
19
from errno import EEXIST
20
20
import os
21
21
 
22
22
from bzrlib import (
23
23
    errors,
 
24
    osutils,
24
25
    revision as _mod_revision,
 
26
    symbol_versioning,
25
27
    )
26
28
from bzrlib.inventory import (
27
29
    Inventory,
29
31
    InventoryDirectory,
30
32
    InventoryLink,
31
33
    )
32
 
from bzrlib.revisiontree import InventoryRevisionTree
33
 
from bzrlib.tests.per_workingtree import TestCaseWithWorkingTree
34
 
from bzrlib.tests import (
35
 
    features,
36
 
    )
 
34
from bzrlib.revision import Revision
 
35
from bzrlib.tests import SymlinkFeature, TestNotApplicable
 
36
from bzrlib.tests.workingtree_implementations import TestCaseWithWorkingTree
37
37
from bzrlib.uncommit import uncommit
38
38
 
39
39
 
227
227
                            (rev3, rev_tree3)])
228
228
        self.assertConsistentParents([rev2, rev3], t)
229
229
 
230
 
    def test_unicode_symlink(self):
231
 
        # this tests bug #272444
232
 
        self.requireFeature(features.SymlinkFeature)
233
 
        self.requireFeature(features.UnicodeFilenameFeature)
234
 
 
235
 
        tree = self.make_branch_and_tree('tree1')
236
 
 
237
 
        # The link points to a file whose name is an omega
238
 
        # U+03A9 GREEK CAPITAL LETTER OMEGA
239
 
        # UTF-8: ce a9  UTF-16BE: 03a9  Decimal: Ω
240
 
        target = u'\u03a9'
241
 
        link_name = u'\N{Euro Sign}link'
242
 
        os.symlink(target, 'tree1/' + link_name)
243
 
        tree.add([link_name], ['link-id'])
244
 
 
245
 
        revision1 = tree.commit('added a link to a Unicode target')
246
 
        revision2 = tree.commit('this revision will be discarded')
247
 
        tree.set_parent_ids([revision1])
248
 
        tree.lock_read()
249
 
        self.addCleanup(tree.unlock)
250
 
        # Check that the symlink target is safely round-tripped in the trees.
251
 
        self.assertEqual(target, tree.get_symlink_target('link-id'))
252
 
        basis = tree.basis_tree()
253
 
        self.assertEqual(target, basis.get_symlink_target('link-id'))
254
 
 
255
230
 
256
231
class TestAddParent(TestParents):
257
232
 
262
237
        uncommit(tree.branch, tree=tree)
263
238
        tree.add_parent_tree_id(first_revision)
264
239
        self.assertConsistentParents([first_revision], tree)
265
 
 
 
240
        
266
241
    def test_add_first_parent_id_ghost_rejects(self):
267
242
        """Test adding the first parent id - as a ghost"""
268
243
        tree = self.make_branch_and_tree('.')
269
244
        self.assertRaises(errors.GhostRevisionUnusableHere,
270
245
            tree.add_parent_tree_id, 'first-revision')
271
 
 
 
246
        
272
247
    def test_add_first_parent_id_ghost_force(self):
273
248
        """Test adding the first parent id - as a ghost"""
274
249
        tree = self.make_branch_and_tree('.')
281
256
        tree.add_parent_tree_id('first-revision', allow_leftmost_as_ghost=True)
282
257
        tree.add_parent_tree_id('second')
283
258
        self.assertConsistentParents(['first-revision', 'second'], tree)
284
 
 
 
259
        
285
260
    def test_add_second_parent_id(self):
286
261
        """Test adding the second parent id"""
287
262
        tree = self.make_branch_and_tree('.')
290
265
        second_revision = tree.commit('second post')
291
266
        tree.add_parent_tree_id(first_revision)
292
267
        self.assertConsistentParents([second_revision, first_revision], tree)
293
 
 
 
268
        
294
269
    def test_add_second_parent_id_ghost(self):
295
270
        """Test adding the second parent id - as a ghost"""
296
271
        tree = self.make_branch_and_tree('.')
297
272
        first_revision = tree.commit('first post')
298
273
        tree.add_parent_tree_id('second')
299
274
        self.assertConsistentParents([first_revision, 'second'], tree)
300
 
 
 
275
        
301
276
    def test_add_first_parent_tree(self):
302
277
        """Test adding the first parent id"""
303
278
        tree = self.make_branch_and_tree('.')
306
281
        tree.add_parent_tree((first_revision,
307
282
            tree.branch.repository.revision_tree(first_revision)))
308
283
        self.assertConsistentParents([first_revision], tree)
309
 
 
 
284
        
310
285
    def test_add_first_parent_tree_ghost_rejects(self):
311
286
        """Test adding the first parent id - as a ghost"""
312
287
        tree = self.make_branch_and_tree('.')
313
288
        self.assertRaises(errors.GhostRevisionUnusableHere,
314
289
            tree.add_parent_tree, ('first-revision', None))
315
 
 
 
290
        
316
291
    def test_add_first_parent_tree_ghost_force(self):
317
292
        """Test adding the first parent id - as a ghost"""
318
293
        tree = self.make_branch_and_tree('.')
319
294
        tree.add_parent_tree(('first-revision', None),
320
295
            allow_leftmost_as_ghost=True)
321
296
        self.assertConsistentParents(['first-revision'], tree)
322
 
 
 
297
        
323
298
    def test_add_second_parent_tree(self):
324
299
        """Test adding the second parent id"""
325
300
        tree = self.make_branch_and_tree('.')
329
304
        tree.add_parent_tree((first_revision,
330
305
            tree.branch.repository.revision_tree(first_revision)))
331
306
        self.assertConsistentParents([second_revision, first_revision], tree)
332
 
 
 
307
        
333
308
    def test_add_second_parent_tree_ghost(self):
334
309
        """Test adding the second parent id - as a ghost"""
335
310
        tree = self.make_branch_and_tree('.')
340
315
 
341
316
class UpdateToOneParentViaDeltaTests(TestCaseWithWorkingTree):
342
317
    """Tests for the update_basis_by_delta call.
343
 
 
 
318
    
344
319
    This is intuitively defined as 'apply an inventory delta to the basis and
345
320
    discard other parents', but for trees that have an inventory that is not
346
321
    managed as a tree-by-id, the implementation requires roughly duplicated
362
337
        # the delta.
363
338
        result_basis = tree.basis_tree()
364
339
        result_basis.lock_read()
365
 
        try:
366
 
            self.assertEqual(expected_inventory, result_basis.root_inventory)
367
 
        finally:
368
 
            result_basis.unlock()
 
340
        self.addCleanup(result_basis.unlock)
 
341
        self.assertEqual(expected_inventory, result_basis.inventory)
369
342
 
370
343
    def make_inv_delta(self, old, new):
371
344
        """Make an inventory delta from two inventories."""
386
359
        return delta
387
360
 
388
361
    def fake_up_revision(self, tree, revid, shape):
389
 
 
390
 
        class ShapeTree(InventoryRevisionTree):
391
 
 
392
 
            def __init__(self, shape):
393
 
                self._repository = tree.branch.repository
394
 
                self._inventory = shape
395
 
 
396
 
            def get_file_text(self, file_id, path=None):
397
 
                ie = self.root_inventory[file_id]
398
 
                if ie.kind != "file":
399
 
                    return ""
400
 
                return 'a' * ie.text_size
401
 
 
402
 
            def get_file(self, file_id, path=None):
403
 
                return StringIO(self.get_file_text(file_id))
404
 
 
405
362
        tree.lock_write()
406
363
        try:
407
 
            if shape.root.revision is None:
408
 
                shape.root.revision = revid
409
 
            builder = tree.branch.get_commit_builder(
410
 
                    parents=[],
411
 
                    timestamp=0,
412
 
                    timezone=None,
413
 
                    committer="Foo Bar <foo@example.com>",
414
 
                    revision_id=revid)
415
 
            shape_tree = ShapeTree(shape)
416
 
            base_tree = tree.branch.repository.revision_tree(
417
 
                    _mod_revision.NULL_REVISION)
418
 
            changes = shape_tree.iter_changes(
419
 
                base_tree)
420
 
            list(builder.record_iter_changes(shape_tree,
421
 
                base_tree.get_revision_id(), changes))
422
 
            builder.finish_inventory()
423
 
            builder.commit("Message")
 
364
            tree.branch.repository.start_write_group()
 
365
            try:
 
366
                if shape.root.revision is None:
 
367
                    shape.root.revision = revid
 
368
                sha1 = tree.branch.repository.add_inventory(revid, shape, [])
 
369
                rev = Revision(timestamp=0,
 
370
                               timezone=None,
 
371
                               committer="Foo Bar <foo@example.com>",
 
372
                               message="Message",
 
373
                               inventory_sha1=sha1,
 
374
                               revision_id=revid)
 
375
                tree.branch.repository.add_revision(revid, rev)
 
376
            except:
 
377
                tree.branch.repository.abort_write_group()
 
378
                raise
 
379
            else:
 
380
                tree.branch.repository.commit_write_group()
424
381
        finally:
425
382
            tree.unlock()
426
383
 
450
407
            self.add_dir(new_shape, new_revid, 'root-id', None, '')
451
408
 
452
409
    def assertTransitionFromBasisToShape(self, basis_shape, basis_revid,
453
 
        new_shape, new_revid, extra_parent=None, set_current_inventory=True):
 
410
        new_shape, new_revid, extra_parent=None):
454
411
        # set the inventory revision ids.
455
412
        basis_shape.revision_id = basis_revid
456
413
        new_shape.revision_id = new_revid
465
422
                parents.append(extra_parent)
466
423
            tree.set_parent_ids(parents)
467
424
        self.fake_up_revision(tree, new_revid, new_shape)
468
 
        if set_current_inventory:
469
 
            # give tree an inventory of new_shape
470
 
            tree._write_inventory(new_shape)
 
425
        # give tree an inventory of new_shape
 
426
        tree._write_inventory(new_shape)
471
427
        self.assertDeltaApplicationResultsInExpectedBasis(tree, new_revid,
472
428
            delta, new_shape)
473
429
        # The tree should be internally consistent; while this is a moderately
474
430
        # large hammer, this is a particularly sensitive area of code, so the
475
431
        # extra assurance is well worth it.
476
432
        tree._validate()
477
 
        # If tree.branch is remote
478
 
        if tree.user_url != tree.branch.user_url:
479
 
            # We have a lightweight checkout, delete both locations
480
 
            tree.branch.bzrdir.root_transport.delete_tree('.')
481
 
        tree.bzrdir.root_transport.delete_tree('.')
 
433
        osutils.rmtree('tree')
482
434
 
483
435
    def test_no_parents_just_root(self):
484
436
        """Test doing an empty commit - no parent, set a root only."""
485
 
        basis_shape = Inventory(root_id=None)  # empty tree
486
 
        new_shape = Inventory()  # tree with a root
 
437
        basis_shape = Inventory(root_id=None) # empty tree
 
438
        new_shape = Inventory() # tree with a root
487
439
        self.assertTransitionFromBasisToShape(basis_shape, None, new_shape,
488
440
            'new_parent')
489
441
 
534
486
        def do_file(inv, revid):
535
487
            self.add_file(inv, revid, 'path-id', 'root-id', 'path', '1' * 32,
536
488
                12)
537
 
 
538
489
        def do_link(inv, revid):
539
490
            self.add_link(inv, revid, 'path-id', 'root-id', 'path', 'target')
540
 
 
541
491
        def do_dir(inv, revid):
542
492
            self.add_dir(inv, revid, 'path-id', 'root-id', 'path')
543
 
 
544
493
        for old_factory in (do_file, do_link, do_dir):
545
494
            for new_factory in (do_file, do_link, do_dir):
546
495
                if old_factory == new_factory:
765
714
        self.add_link(new_shape, old_revid, 'link-id-C', 'dir-id-B', 'C', 'D')
766
715
        self.assertTransitionFromBasisToShape(basis_shape, old_revid,
767
716
            new_shape, new_revid)
768
 
 
769
 
    def test_add_files_to_empty_directory(self):
770
 
        old_revid = 'old-parent'
771
 
        basis_shape = Inventory(root_id=None)
772
 
        self.add_dir(basis_shape, old_revid, 'root-id', None, '')
773
 
        self.add_dir(basis_shape, old_revid, 'dir-id-A', 'root-id', 'A')
774
 
        new_revid = 'new-parent'
775
 
        new_shape = Inventory(root_id=None)
776
 
        self.add_new_root(new_shape, old_revid, new_revid)
777
 
        self.add_dir(new_shape, old_revid, 'dir-id-A', 'root-id', 'A')
778
 
        self.add_file(new_shape, new_revid, 'file-id-B', 'dir-id-A', 'B',
779
 
            '1' * 32, 24)
780
 
        self.assertTransitionFromBasisToShape(basis_shape, old_revid,
781
 
                new_shape, new_revid, set_current_inventory=False)