~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

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

Merge from bzr.dev.

Show diffs side-by-side

added added

removed removed

Lines of Context:
16
16
 
17
17
"""Tests of the parent related functions of WorkingTrees."""
18
18
 
 
19
from errno import EEXIST
19
20
import os
20
21
 
21
22
from bzrlib import (
22
23
    errors,
 
24
    osutils,
23
25
    revision as _mod_revision,
24
26
    symbol_versioning,
25
27
    )
 
28
from bzrlib.inventory import (
 
29
    Inventory,
 
30
    InventoryFile,
 
31
    InventoryDirectory,
 
32
    InventoryLink,
 
33
    )
 
34
from bzrlib.revision import Revision
 
35
from bzrlib.tests import SymlinkFeature, TestNotApplicable
26
36
from bzrlib.tests.workingtree_implementations import TestCaseWithWorkingTree
27
37
from bzrlib.uncommit import uncommit
28
38
 
237
247
        first_revision = tree.commit('first post')
238
248
        tree.add_parent_tree(('second', None))
239
249
        self.assertConsistentParents([first_revision, 'second'], tree)
 
250
 
 
251
 
 
252
class UpdateToOneParentViaDeltaTests(TestParents):
 
253
    """Tests for the update_to_one_parent_via_delta call.
 
254
    
 
255
    This is intuitively defined as 'apply an inventory delta to the basis and
 
256
    discard other parents', but for trees that have an inventory that is not
 
257
    managed as a tree-by-id, the implementation requires roughly duplicated
 
258
    tests with those for apply_inventory_delta on the main tree.
 
259
    """
 
260
 
 
261
    def assertDeltaApplicationResultsInExpectedBasis(self, tree, revid, delta,
 
262
        expected_inventory):
 
263
        tree.update_to_one_parent_via_delta(revid, delta)
 
264
        # check the last revision was adjusted to rev_id
 
265
        self.assertEqual(revid, tree.last_revision())
 
266
        # check the parents are what we expect
 
267
        self.assertEqual([revid], tree.get_parent_ids())
 
268
        # check that the basis tree has the inventory we expect from applying
 
269
        # the delta.
 
270
        result_basis = tree.basis_tree()
 
271
        result_basis.lock_read()
 
272
        self.addCleanup(result_basis.unlock)
 
273
        self.assertEqual(expected_inventory, result_basis.inventory)
 
274
 
 
275
    def make_inv_delta(self, old, new):
 
276
        """Make an inventory delta from two inventories."""
 
277
        old_ids = set(old._byid.iterkeys())
 
278
        new_ids = set(new._byid.iterkeys())
 
279
        adds = new_ids - old_ids
 
280
        deletes = old_ids - new_ids
 
281
        common = old_ids.intersection(new_ids)
 
282
        delta = []
 
283
        for file_id in deletes:
 
284
            delta.append((old.id2path(file_id), None, file_id, None))
 
285
        for file_id in adds:
 
286
            delta.append((None, new.id2path(file_id), file_id, new[file_id]))
 
287
        for file_id in common:
 
288
            if old[file_id] != new[file_id]:
 
289
                delta.append((old.id2path(file_id), new.id2path(file_id),
 
290
                    file_id, new[file_id]))
 
291
        return delta
 
292
 
 
293
    def fake_up_revision(self, tree, revid, shape):
 
294
        tree.lock_write()
 
295
        try:
 
296
            tree.branch.repository.start_write_group()
 
297
            try:
 
298
                if shape.root.revision is None:
 
299
                    shape.root.revision = revid
 
300
                sha1 = tree.branch.repository.add_inventory(revid, shape, [])
 
301
                rev = Revision(timestamp=0,
 
302
                               timezone=None,
 
303
                               committer="Foo Bar <foo@example.com>",
 
304
                               message="Message",
 
305
                               inventory_sha1=sha1,
 
306
                               revision_id=revid)
 
307
                tree.branch.repository.add_revision(revid, rev)
 
308
            except:
 
309
                tree.branch.repository.abort_write_group()
 
310
                raise
 
311
            else:
 
312
                tree.branch.repository.commit_write_group()
 
313
        finally:
 
314
            tree.unlock()
 
315
 
 
316
    def add_entry(self, inv, rev_id, entry):
 
317
        entry.revision = rev_id
 
318
        inv.add(entry)
 
319
 
 
320
    def add_dir(self, inv, rev_id, file_id, parent_id, name):
 
321
        new_dir = InventoryDirectory(file_id, name, parent_id)
 
322
        self.add_entry(inv, rev_id, new_dir)
 
323
 
 
324
    def add_file(self, inv, rev_id, file_id, parent_id, name, sha, size):
 
325
        new_file = InventoryFile(file_id, name, parent_id)
 
326
        new_file.text_sha1 = sha
 
327
        new_file.text_size = size
 
328
        self.add_entry(inv, rev_id, new_file)
 
329
 
 
330
    def add_link(self, inv, rev_id, file_id, parent_id, name, target):
 
331
        new_link = InventoryLink(file_id, name, parent_id)
 
332
        new_link.symlink_target = target
 
333
        self.add_entry(inv, rev_id, new_link)
 
334
 
 
335
    def add_new_root(self, new_shape, old_revid, new_revid):
 
336
        if self.bzrdir_format.repository_format.rich_root_data:
 
337
            self.add_dir(new_shape, old_revid, 'root-id', None, '')
 
338
        else:
 
339
            self.add_dir(new_shape, new_revid, 'root-id', None, '')
 
340
 
 
341
    def assertTransitionFromBasisToShape(self, basis_shape, basis_revid,
 
342
        new_shape, new_revid, extra_parent=None):
 
343
        delta = self.make_inv_delta(basis_shape, new_shape)
 
344
        tree = self.make_branch_and_tree('tree')
 
345
        # the shapes need to be in the tree's repository to be able to set them
 
346
        # as a parent, but the file content is not needed.
 
347
        if basis_revid is not None:
 
348
            self.fake_up_revision(tree, basis_revid, basis_shape)
 
349
            parents = [basis_revid]
 
350
            if extra_parent is not None:
 
351
                parents.append(extra_parent)
 
352
            tree.set_parent_ids(parents)
 
353
        self.fake_up_revision(tree, new_revid, new_shape)
 
354
        self.assertDeltaApplicationResultsInExpectedBasis(tree, new_revid,
 
355
            delta, new_shape)
 
356
        osutils.rmtree('tree')
 
357
 
 
358
    def test_no_parents_just_root(self):
 
359
        """Test doing an empty commit - no parent, set a root only."""
 
360
        basis_shape = Inventory(root_id=None) # empty tree
 
361
        new_shape = Inventory() # tree with a root
 
362
        self.assertTransitionFromBasisToShape(basis_shape, None, new_shape,
 
363
            'new_parent')
 
364
 
 
365
    def test_no_parents_full_tree(self):
 
366
        """Test doing a regular initial commit with files and dirs."""
 
367
        basis_shape = Inventory(root_id=None) # empty tree
 
368
        revid = 'new-parent'
 
369
        new_shape = Inventory(root_id=None)
 
370
        self.add_dir(new_shape, revid, 'root-id', None, '')
 
371
        self.add_link(new_shape, revid, 'link-id', 'root-id', 'link', 'target')
 
372
        self.add_file(new_shape, revid, 'file-id', 'root-id', 'file', '1' * 32,
 
373
            12)
 
374
        self.add_dir(new_shape, revid, 'dir-id', 'root-id', 'dir')
 
375
        self.add_file(new_shape, revid, 'subfile-id', 'dir-id', 'subfile',
 
376
            '2' * 32, 24)
 
377
        self.assertTransitionFromBasisToShape(basis_shape, None, new_shape,
 
378
            revid)
 
379
 
 
380
    def test_file_content_change(self):
 
381
        old_revid = 'old-parent'
 
382
        basis_shape = Inventory(root_id=None)
 
383
        self.add_dir(basis_shape, old_revid, 'root-id', None, '')
 
384
        self.add_file(basis_shape, old_revid, 'file-id', 'root-id', 'file',
 
385
            '1' * 32, 12)
 
386
        new_revid = 'new-parent'
 
387
        new_shape = Inventory(root_id=None)
 
388
        self.add_new_root(new_shape, old_revid, new_revid)
 
389
        self.add_file(new_shape, new_revid, 'file-id', 'root-id', 'file',
 
390
            '2' * 32, 24)
 
391
        self.assertTransitionFromBasisToShape(basis_shape, old_revid,
 
392
            new_shape, new_revid)
 
393
 
 
394
    def test_link_content_change(self):
 
395
        old_revid = 'old-parent'
 
396
        basis_shape = Inventory(root_id=None)
 
397
        self.add_dir(basis_shape, old_revid, 'root-id', None, '')
 
398
        self.add_link(basis_shape, old_revid, 'link-id', 'root-id', 'link',
 
399
            'old-target')
 
400
        new_revid = 'new-parent'
 
401
        new_shape = Inventory(root_id=None)
 
402
        self.add_new_root(new_shape, old_revid, new_revid)
 
403
        self.add_link(new_shape, new_revid, 'link-id', 'root-id', 'link',
 
404
            'new-target')
 
405
        self.assertTransitionFromBasisToShape(basis_shape, old_revid,
 
406
            new_shape, new_revid)
 
407
 
 
408
    def test_kind_changes(self):
 
409
        def do_file(inv, revid):
 
410
            self.add_file(inv, revid, 'path-id', 'root-id', 'path', '1' * 32,
 
411
                12)
 
412
        def do_link(inv, revid):
 
413
            self.add_link(inv, revid, 'path-id', 'root-id', 'path', 'target')
 
414
        def do_dir(inv, revid):
 
415
            self.add_dir(inv, revid, 'path-id', 'root-id', 'path')
 
416
        for old_factory in (do_file, do_link, do_dir):
 
417
            for new_factory in (do_file, do_link, do_dir):
 
418
                if old_factory == new_factory:
 
419
                    continue
 
420
                old_revid = 'old-parent'
 
421
                basis_shape = Inventory(root_id=None)
 
422
                self.add_dir(basis_shape, old_revid, 'root-id', None, '')
 
423
                old_factory(basis_shape, old_revid)
 
424
                new_revid = 'new-parent'
 
425
                new_shape = Inventory(root_id=None)
 
426
                self.add_new_root(new_shape, old_revid, new_revid)
 
427
                new_factory(new_shape, new_revid)
 
428
                self.assertTransitionFromBasisToShape(basis_shape, old_revid,
 
429
                    new_shape, new_revid)
 
430
 
 
431
    def test_content_from_second_parent_is_dropped(self):
 
432
        left_revid = 'left-parent'
 
433
        basis_shape = Inventory(root_id=None)
 
434
        self.add_dir(basis_shape, left_revid, 'root-id', None, '')
 
435
        self.add_link(basis_shape, left_revid, 'link-id', 'root-id', 'link',
 
436
            'left-target')
 
437
        # the right shape has content - file, link, subdir with a child,
 
438
        # that should all be discarded by the call.
 
439
        right_revid = 'right-parent'
 
440
        right_shape = Inventory(root_id=None)
 
441
        self.add_dir(right_shape, left_revid, 'root-id', None, '')
 
442
        self.add_link(right_shape, right_revid, 'link-id', 'root-id', 'link',
 
443
            'some-target')
 
444
        self.add_dir(right_shape, right_revid, 'subdir-id', 'root-id', 'dir')
 
445
        self.add_file(right_shape, right_revid, 'file-id', 'subdir-id', 'file',
 
446
            '2' * 32, 24)
 
447
        new_revid = 'new-parent'
 
448
        new_shape = Inventory(root_id=None)
 
449
        self.add_new_root(new_shape, left_revid, new_revid)
 
450
        self.add_link(new_shape, new_revid, 'link-id', 'root-id', 'link',
 
451
            'new-target')
 
452
        self.assertTransitionFromBasisToShape(basis_shape, left_revid,
 
453
            new_shape, new_revid, right_revid)
 
454
 
 
455
    def test_parent_id_changed(self):
 
456
        # test that when the only change to an entry is its parent id changing
 
457
        # that it is handled correctly (that is it keeps the same path)
 
458
        old_revid = 'old-parent'
 
459
        basis_shape = Inventory(root_id=None)
 
460
        self.add_dir(basis_shape, old_revid, 'root-id', None, '')
 
461
        self.add_dir(basis_shape, old_revid, 'orig-parent-id', 'root-id', 'dir')
 
462
        self.add_dir(basis_shape, old_revid, 'dir-id', 'orig-parent-id', 'dir')
 
463
        new_revid = 'new-parent'
 
464
        new_shape = Inventory(root_id=None)
 
465
        self.add_new_root(new_shape, old_revid, new_revid)
 
466
        self.add_dir(new_shape, new_revid, 'new-parent-id', 'root-id', 'dir')
 
467
        self.add_dir(new_shape, new_revid, 'dir-id', 'new-parent-id', 'dir')
 
468
        self.assertTransitionFromBasisToShape(basis_shape, old_revid,
 
469
            new_shape, new_revid)
 
470
 
 
471
    def test_name_changed(self):
 
472
        # test that when the only change to an entry is its name changing that
 
473
        # it is handled correctly (that is it keeps the same parent id)
 
474
        old_revid = 'old-parent'
 
475
        basis_shape = Inventory(root_id=None)
 
476
        self.add_dir(basis_shape, old_revid, 'root-id', None, '')
 
477
        self.add_dir(basis_shape, old_revid, 'parent-id', 'root-id', 'origdir')
 
478
        self.add_dir(basis_shape, old_revid, 'dir-id', 'parent-id', 'olddir')
 
479
        new_revid = 'new-parent'
 
480
        new_shape = Inventory(root_id=None)
 
481
        self.add_new_root(new_shape, old_revid, new_revid)
 
482
        self.add_dir(new_shape, new_revid, 'parent-id', 'root-id', 'newdir')
 
483
        self.add_dir(new_shape, new_revid, 'dir-id', 'parent-id', 'newdir')
 
484
        self.assertTransitionFromBasisToShape(basis_shape, old_revid,
 
485
            new_shape, new_revid)
 
486
 
 
487
    def test_path_swap(self):
 
488
        # test a A->B and B->A path swap.
 
489
        old_revid = 'old-parent'
 
490
        basis_shape = Inventory(root_id=None)
 
491
        self.add_dir(basis_shape, old_revid, 'root-id', None, '')
 
492
        self.add_dir(basis_shape, old_revid, 'dir-id-A', 'root-id', 'A')
 
493
        self.add_dir(basis_shape, old_revid, 'dir-id-B', 'root-id', 'B')
 
494
        self.add_link(basis_shape, old_revid, 'link-id-C', 'root-id', 'C', 'C')
 
495
        self.add_link(basis_shape, old_revid, 'link-id-D', 'root-id', 'D', 'D')
 
496
        self.add_file(basis_shape, old_revid, 'file-id-E', 'root-id', 'E',
 
497
            '1' * 32, 12)
 
498
        self.add_file(basis_shape, old_revid, 'file-id-F', 'root-id', 'F',
 
499
            '2' * 32, 24)
 
500
        new_revid = 'new-parent'
 
501
        new_shape = Inventory(root_id=None)
 
502
        self.add_new_root(new_shape, old_revid, new_revid)
 
503
        self.add_dir(new_shape, new_revid, 'dir-id-A', 'root-id', 'B')
 
504
        self.add_dir(new_shape, new_revid, 'dir-id-B', 'root-id', 'A')
 
505
        self.add_link(new_shape, new_revid, 'link-id-C', 'root-id', 'D', 'C')
 
506
        self.add_link(new_shape, new_revid, 'link-id-D', 'root-id', 'C', 'D')
 
507
        self.add_file(new_shape, new_revid, 'file-id-E', 'root-id', 'F',
 
508
            '1' * 32, 12)
 
509
        self.add_file(new_shape, new_revid, 'file-id-F', 'root-id', 'E',
 
510
            '2' * 32, 24)
 
511
        self.assertTransitionFromBasisToShape(basis_shape, old_revid,
 
512
            new_shape, new_revid)
 
513
 
 
514
    def test_adds(self):
 
515
        # test adding paths and dirs, including adding to a newly added dir.
 
516
        old_revid = 'old-parent'
 
517
        basis_shape = Inventory(root_id=None)
 
518
        # with a root, so its a commit after the first.
 
519
        self.add_dir(basis_shape, old_revid, 'root-id', None, '')
 
520
        new_revid = 'new-parent'
 
521
        new_shape = Inventory(root_id=None)
 
522
        self.add_new_root(new_shape, old_revid, new_revid)
 
523
        self.add_dir(new_shape, new_revid, 'dir-id-A', 'root-id', 'A')
 
524
        self.add_link(new_shape, new_revid, 'link-id-B', 'root-id', 'B', 'C')
 
525
        self.add_file(new_shape, new_revid, 'file-id-C', 'root-id', 'C',
 
526
            '1' * 32, 12)
 
527
        self.add_file(new_shape, new_revid, 'file-id-D', 'dir-id-A', 'D',
 
528
            '2' * 32, 24)
 
529
        self.assertTransitionFromBasisToShape(basis_shape, old_revid,
 
530
            new_shape, new_revid)
 
531
 
 
532
    def test_removes(self):
 
533
        # test removing paths, including paths that are within other also
 
534
        # removed paths.
 
535
        old_revid = 'old-parent'
 
536
        basis_shape = Inventory(root_id=None)
 
537
        self.add_dir(basis_shape, old_revid, 'root-id', None, '')
 
538
        self.add_dir(basis_shape, old_revid, 'dir-id-A', 'root-id', 'A')
 
539
        self.add_link(basis_shape, old_revid, 'link-id-B', 'root-id', 'B', 'C')
 
540
        self.add_file(basis_shape, old_revid, 'file-id-C', 'root-id', 'C',
 
541
            '1' * 32, 12)
 
542
        self.add_file(basis_shape, old_revid, 'file-id-D', 'dir-id-A', 'D',
 
543
            '2' * 32, 24)
 
544
        new_revid = 'new-parent'
 
545
        new_shape = Inventory(root_id=None)
 
546
        self.add_new_root(new_shape, old_revid, new_revid)
 
547
        self.assertTransitionFromBasisToShape(basis_shape, old_revid,
 
548
            new_shape, new_revid)
 
549
 
 
550
    def test_move_to_added_dir(self):
 
551
        old_revid = 'old-parent'
 
552
        basis_shape = Inventory(root_id=None)
 
553
        self.add_dir(basis_shape, old_revid, 'root-id', None, '')
 
554
        self.add_link(basis_shape, old_revid, 'link-id-B', 'root-id', 'B', 'C')
 
555
        new_revid = 'new-parent'
 
556
        new_shape = Inventory(root_id=None)
 
557
        self.add_new_root(new_shape, old_revid, new_revid)
 
558
        self.add_dir(new_shape, new_revid, 'dir-id-A', 'root-id', 'A')
 
559
        self.add_link(new_shape, new_revid, 'link-id-B', 'dir-id-A', 'B', 'C')
 
560
        self.assertTransitionFromBasisToShape(basis_shape, old_revid,
 
561
            new_shape, new_revid)
 
562
 
 
563
    def test_move_from_removed_dir(self):
 
564
        old_revid = 'old-parent'
 
565
        basis_shape = Inventory(root_id=None)
 
566
        self.add_dir(basis_shape, old_revid, 'root-id', None, '')
 
567
        self.add_dir(basis_shape, old_revid, 'dir-id-A', 'root-id', 'A')
 
568
        self.add_link(basis_shape, old_revid, 'link-id-B', 'dir-id-A', 'B', 'C')
 
569
        new_revid = 'new-parent'
 
570
        new_shape = Inventory(root_id=None)
 
571
        self.add_new_root(new_shape, old_revid, new_revid)
 
572
        self.add_link(new_shape, new_revid, 'link-id-B', 'root-id', 'B', 'C')
 
573
        self.assertTransitionFromBasisToShape(basis_shape, old_revid,
 
574
            new_shape, new_revid)