~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/test_transform.py

  • Committer: Richard Wilbur
  • Date: 2016-02-04 19:07:28 UTC
  • mto: This revision was merged to the branch mainline in revision 6618.
  • Revision ID: richard.wilbur@gmail.com-20160204190728-p0zvfii6zase0fw7
Update COPYING.txt from the original http://www.gnu.org/licenses/gpl-2.0.txt  (Only differences were in whitespace.)  Thanks to Petr Stodulka for pointing out the discrepancy.

Show diffs side-by-side

added added

removed removed

Lines of Context:
34
34
    transform,
35
35
    urlutils,
36
36
    )
37
 
from bzrlib.bzrdir import BzrDir
38
37
from bzrlib.conflicts import (
39
38
    DeletingParent,
40
39
    DuplicateEntry,
44
43
    ParentLoop,
45
44
    UnversionedParent,
46
45
)
 
46
from bzrlib.controldir import ControlDir
47
47
from bzrlib.diff import show_diff_trees
48
48
from bzrlib.errors import (
49
49
    DuplicateKey,
60
60
    pathjoin,
61
61
)
62
62
from bzrlib.merge import Merge3Merger, Merger
 
63
from bzrlib.mutabletree import MutableTree
63
64
from bzrlib.tests import (
64
65
    features,
 
66
    TestCaseInTempDir,
 
67
    TestSkipped,
 
68
    )
 
69
from bzrlib.tests.features import (
65
70
    HardlinkFeature,
66
71
    SymlinkFeature,
67
 
    TestCaseInTempDir,
68
 
    TestSkipped,
69
 
)
 
72
    )
70
73
from bzrlib.transform import (
71
74
    build_tree,
72
75
    create_from_tree,
85
88
 
86
89
    def setUp(self):
87
90
        super(TestTreeTransform, self).setUp()
88
 
        self.wt = self.make_branch_and_tree('.', format='dirstate-with-subtree')
 
91
        self.wt = self.make_branch_and_tree('.', format='development-subtree')
89
92
        os.chdir('..')
90
93
 
91
94
    def get_transform(self):
285
288
        new_trans_id = transform.new_directory('', ROOT_PARENT, 'alt-root-id')
286
289
        self.assertRaises(ValueError, transform.fixup_new_roots)
287
290
 
 
291
    def test_retain_existing_root(self):
 
292
        tt, root = self.get_transform()
 
293
        with tt:
 
294
            tt.new_directory('', ROOT_PARENT, 'new-root-id')
 
295
            tt.fixup_new_roots()
 
296
            self.assertNotEqual('new-root-id', tt.final_file_id(tt.root))
 
297
 
 
298
    def test_retain_existing_root_added_file(self):
 
299
        tt, root = self.get_transform()
 
300
        new_trans_id = tt.new_directory('', ROOT_PARENT, 'new-root-id')
 
301
        child = tt.new_directory('child', new_trans_id, 'child-id')
 
302
        tt.fixup_new_roots()
 
303
        self.assertEqual(tt.root, tt.final_parent(child))
 
304
 
 
305
    def test_add_unversioned_root(self):
 
306
        transform, root = self.get_transform()
 
307
        new_trans_id = transform.new_directory('', ROOT_PARENT, None)
 
308
        transform.delete_contents(transform.root)
 
309
        transform.fixup_new_roots()
 
310
        self.assertNotIn(transform.root, transform._new_id)
 
311
 
 
312
    def test_remove_root_fixup(self):
 
313
        transform, root = self.get_transform()
 
314
        old_root_id = self.wt.get_root_id()
 
315
        self.assertNotEqual('new-root-id', old_root_id)
 
316
        transform.delete_contents(root)
 
317
        transform.unversion_file(root)
 
318
        transform.fixup_new_roots()
 
319
        transform.apply()
 
320
        self.assertEqual(old_root_id, self.wt.get_root_id())
 
321
 
 
322
        transform, root = self.get_transform()
 
323
        new_trans_id = transform.new_directory('', ROOT_PARENT, 'new-root-id')
 
324
        new_trans_id = transform.new_directory('', ROOT_PARENT, 'alt-root-id')
 
325
        self.assertRaises(ValueError, transform.fixup_new_roots)
 
326
 
 
327
    def test_fixup_new_roots_permits_empty_tree(self):
 
328
        transform, root = self.get_transform()
 
329
        transform.delete_contents(root)
 
330
        transform.unversion_file(root)
 
331
        transform.fixup_new_roots()
 
332
        self.assertIs(None, transform.final_kind(root))
 
333
        self.assertIs(None, transform.final_file_id(root))
 
334
 
 
335
    def test_apply_retains_root_directory(self):
 
336
        # Do not attempt to delete the physical root directory, because that
 
337
        # is impossible.
 
338
        transform, root = self.get_transform()
 
339
        with transform:
 
340
            transform.delete_contents(root)
 
341
            e = self.assertRaises(AssertionError, self.assertRaises,
 
342
                                  errors.TransformRenameFailed,
 
343
                                  transform.apply)
 
344
        self.assertContainsRe('TransformRenameFailed not raised', str(e))
 
345
 
 
346
    def test_apply_retains_file_id(self):
 
347
        transform, root = self.get_transform()
 
348
        old_root_id = transform.tree_file_id(root)
 
349
        transform.unversion_file(root)
 
350
        transform.apply()
 
351
        self.assertEqual(old_root_id, self.wt.get_root_id())
 
352
 
288
353
    def test_hardlink(self):
289
354
        self.requireFeature(HardlinkFeature)
290
355
        transform, root = self.get_transform()
334
399
        tree.lock_read()
335
400
        self.addCleanup(tree.unlock)
336
401
        self.assertEqual('subtree-revision',
337
 
                         tree.inventory['subtree-id'].reference_revision)
 
402
                         tree.root_inventory['subtree-id'].reference_revision)
338
403
 
339
404
    def test_conflicts(self):
340
405
        transform, root = self.get_transform()
717
782
                            'wizard2', 'behind_curtain')
718
783
 
719
784
    def test_symlinks_unicode(self):
720
 
        self.requireFeature(tests.UnicodeFilenameFeature)
 
785
        self.requireFeature(features.UnicodeFilenameFeature)
721
786
        self._test_symlinks(u'\N{Euro Sign}wizard',
722
787
                            u'wizard-targ\N{Euro Sign}t',
723
788
                            u'\N{Euro Sign}wizard2',
811
876
        raw_conflicts = resolve_conflicts(tt)
812
877
        cooked_conflicts = cook_conflicts(raw_conflicts, tt)
813
878
        tt.finalize()
814
 
        conflicts_s = [str(c) for c in cooked_conflicts]
 
879
        conflicts_s = [unicode(c) for c in cooked_conflicts]
815
880
        self.assertEqual(len(cooked_conflicts), len(conflicts_s))
816
881
        self.assertEqual(conflicts_s[0], 'Conflict adding file dorothy.  '
817
882
                                         'Moved existing file to '
1412
1477
        # The rename will fail because the target directory is not empty (but
1413
1478
        # raises FileExists anyway).
1414
1479
        err = self.assertRaises(errors.FileExists, tt_helper)
1415
 
        self.assertContainsRe(str(err),
1416
 
            "^File exists: .+/baz")
 
1480
        self.assertEndsWith(err.path, "/baz")
1417
1481
 
1418
1482
    def test_two_directories_clash(self):
1419
1483
        def tt_helper():
1431
1495
                wt.unlock()
1432
1496
                raise
1433
1497
        err = self.assertRaises(errors.FileExists, tt_helper)
1434
 
        self.assertContainsRe(str(err),
1435
 
            "^File exists: .+/foo")
 
1498
        self.assertEndsWith(err.path, "/foo")
1436
1499
 
1437
1500
    def test_two_directories_clash_finalize(self):
1438
1501
        def tt_helper():
1450
1513
                tt.finalize()
1451
1514
                raise
1452
1515
        err = self.assertRaises(errors.FileExists, tt_helper)
1453
 
        self.assertContainsRe(str(err),
1454
 
            "^File exists: .+/foo")
 
1516
        self.assertEndsWith(err.path, "/foo")
1455
1517
 
1456
1518
    def test_file_to_directory(self):
1457
1519
        wt = self.make_branch_and_tree('.')
1470
1532
        self.assertPathExists("foo/bar")
1471
1533
        wt.lock_read()
1472
1534
        try:
1473
 
            self.assertEqual(wt.inventory.get_file_kind(wt.path2id("foo")),
1474
 
                    "directory")
 
1535
            self.assertEqual(wt.kind(wt.path2id("foo")), "directory")
1475
1536
        finally:
1476
1537
            wt.unlock()
1477
1538
        wt.commit("two")
1493
1554
        self.assertPathExists("foo")
1494
1555
        wt.lock_read()
1495
1556
        self.addCleanup(wt.unlock)
1496
 
        self.assertEqual(wt.inventory.get_file_kind(wt.path2id("foo")),
1497
 
                "symlink")
 
1557
        self.assertEqual(wt.kind(wt.path2id("foo")), "symlink")
1498
1558
 
1499
1559
    def test_dir_to_file(self):
1500
1560
        wt = self.make_branch_and_tree('.')
1512
1572
        self.assertPathExists("foo")
1513
1573
        wt.lock_read()
1514
1574
        self.addCleanup(wt.unlock)
1515
 
        self.assertEqual(wt.inventory.get_file_kind(wt.path2id("foo")),
1516
 
                "file")
 
1575
        self.assertEqual(wt.kind(wt.path2id("foo")), "file")
1517
1576
 
1518
1577
    def test_dir_to_hardlink(self):
1519
1578
        self.requireFeature(HardlinkFeature)
1534
1593
        self.assertPathExists("baz")
1535
1594
        wt.lock_read()
1536
1595
        self.addCleanup(wt.unlock)
1537
 
        self.assertEqual(wt.inventory.get_file_kind(wt.path2id("foo")),
1538
 
                "file")
 
1596
        self.assertEqual(wt.kind(wt.path2id("foo")), "file")
1539
1597
 
1540
1598
    def test_no_final_path(self):
1541
1599
        transform, root = self.get_transform()
1587
1645
    def __init__(self, dirname, root_id):
1588
1646
        self.name = dirname
1589
1647
        os.mkdir(dirname)
1590
 
        self.wt = BzrDir.create_standalone_workingtree(dirname)
 
1648
        self.wt = ControlDir.create_standalone_workingtree(dirname)
1591
1649
        self.wt.set_root_id(root_id)
1592
1650
        self.b = self.wt.branch
1593
1651
        self.tt = TreeTransform(self.wt)
1599
1657
    return template % ('<' * 7, tree, '=' * 7, merge, '>' * 7)
1600
1658
 
1601
1659
 
 
1660
class TestInventoryAltered(tests.TestCaseWithTransport):
 
1661
 
 
1662
    def test_inventory_altered_unchanged(self):
 
1663
        tree = self.make_branch_and_tree('tree')
 
1664
        self.build_tree(['tree/foo'])
 
1665
        tree.add('foo', 'foo-id')
 
1666
        with TransformPreview(tree) as tt:
 
1667
            self.assertEqual([], tt._inventory_altered())
 
1668
 
 
1669
    def test_inventory_altered_changed_parent_id(self):
 
1670
        tree = self.make_branch_and_tree('tree')
 
1671
        self.build_tree(['tree/foo'])
 
1672
        tree.add('foo', 'foo-id')
 
1673
        with TransformPreview(tree) as tt:
 
1674
            tt.unversion_file(tt.root)
 
1675
            tt.version_file('new-id', tt.root)
 
1676
            foo_trans_id = tt.trans_id_tree_file_id('foo-id')
 
1677
            foo_tuple = ('foo', foo_trans_id)
 
1678
            root_tuple = ('', tt.root)
 
1679
            self.assertEqual([root_tuple, foo_tuple], tt._inventory_altered())
 
1680
 
 
1681
    def test_inventory_altered_noop_changed_parent_id(self):
 
1682
        tree = self.make_branch_and_tree('tree')
 
1683
        self.build_tree(['tree/foo'])
 
1684
        tree.add('foo', 'foo-id')
 
1685
        with TransformPreview(tree) as tt:
 
1686
            tt.unversion_file(tt.root)
 
1687
            tt.version_file(tree.get_root_id(), tt.root)
 
1688
            foo_trans_id = tt.trans_id_tree_file_id('foo-id')
 
1689
            self.assertEqual([], tt._inventory_altered())
 
1690
 
 
1691
 
1602
1692
class TestTransformMerge(TestCaseInTempDir):
1603
1693
 
1604
1694
    def test_text_merge(self):
1671
1761
        merge_modified = this.wt.merge_modified()
1672
1762
        self.assertSubset(merge_modified, modified)
1673
1763
        self.assertEqual(len(merge_modified), len(modified))
1674
 
        file(this.wt.id2abspath('a'), 'wb').write('booga')
 
1764
        with file(this.wt.id2abspath('a'), 'wb') as f: f.write('booga')
1675
1765
        modified.pop(0)
1676
1766
        merge_modified = this.wt.merge_modified()
1677
1767
        self.assertSubset(merge_modified, modified)
1791
1881
    def test_build_tree_with_symlinks(self):
1792
1882
        self.requireFeature(SymlinkFeature)
1793
1883
        os.mkdir('a')
1794
 
        a = BzrDir.create_standalone_workingtree('a')
 
1884
        a = ControlDir.create_standalone_workingtree('a')
1795
1885
        os.mkdir('a/foo')
1796
 
        file('a/foo/bar', 'wb').write('contents')
 
1886
        with file('a/foo/bar', 'wb') as f: f.write('contents')
1797
1887
        os.symlink('a/foo/bar', 'a/foo/baz')
1798
1888
        a.add(['foo', 'foo/bar', 'foo/baz'])
1799
1889
        a.commit('initial commit')
1800
 
        b = BzrDir.create_standalone_workingtree('b')
 
1890
        b = ControlDir.create_standalone_workingtree('b')
1801
1891
        basis = a.basis_tree()
1802
1892
        basis.lock_read()
1803
1893
        self.addCleanup(basis.unlock)
1808
1898
 
1809
1899
    def test_build_with_references(self):
1810
1900
        tree = self.make_branch_and_tree('source',
1811
 
            format='dirstate-with-subtree')
 
1901
            format='development-subtree')
1812
1902
        subtree = self.make_branch_and_tree('source/subtree',
1813
 
            format='dirstate-with-subtree')
 
1903
            format='development-subtree')
1814
1904
        tree.add_reference(subtree)
1815
1905
        tree.commit('a revision')
1816
1906
        tree.branch.create_checkout('target')
2094
2184
        def rot13(chunks, context=None):
2095
2185
            return [''.join(chunks).encode('rot13')]
2096
2186
        rot13filter = filters.ContentFilter(rot13, rot13)
2097
 
        filters.register_filter_stack_map('rot13', {'yes': [rot13filter]}.get)
 
2187
        filters.filter_stacks_registry.register(
 
2188
            'rot13', {'yes': [rot13filter]}.get)
2098
2189
        os.mkdir(self.test_home_dir + '/.bazaar')
2099
2190
        rules_filename = self.test_home_dir + '/.bazaar/rules'
2100
2191
        f = open(rules_filename, 'wb')
2130
2221
        self.assertEqualStat(source_stat, target_stat)
2131
2222
 
2132
2223
    def test_case_insensitive_build_tree_inventory(self):
2133
 
        if (tests.CaseInsensitiveFilesystemFeature.available()
2134
 
            or tests.CaseInsCasePresFilenameFeature.available()):
 
2224
        if (features.CaseInsensitiveFilesystemFeature.available()
 
2225
            or features.CaseInsCasePresFilenameFeature.available()):
2135
2226
            raise tests.UnavailableFeature('Fully case sensitive filesystem')
2136
2227
        source = self.make_branch_and_tree('source')
2137
2228
        self.build_tree(['source/file', 'source/FILE'])
2320
2411
        self.assertEqual('tree', revision.properties['branch-nick'])
2321
2412
 
2322
2413
 
2323
 
class TestBackupName(tests.TestCase):
2324
 
 
2325
 
    def test_deprecations(self):
2326
 
        class MockTransform(object):
2327
 
 
2328
 
            def has_named_child(self, by_parent, parent_id, name):
2329
 
                return name in by_parent.get(parent_id, [])
2330
 
 
2331
 
        class MockEntry(object):
2332
 
 
2333
 
            def __init__(self):
2334
 
                object.__init__(self)
2335
 
                self.name = "name"
2336
 
 
2337
 
        tt = MockTransform()
2338
 
        name1 = self.applyDeprecated(
2339
 
            symbol_versioning.deprecated_in((2, 3, 0)),
2340
 
            transform.get_backup_name, MockEntry(), {'a':[]}, 'a', tt)
2341
 
        self.assertEqual('name.~1~', name1)
2342
 
        name2 = self.applyDeprecated(
2343
 
            symbol_versioning.deprecated_in((2, 3, 0)),
2344
 
            transform._get_backup_name, 'name', {'a':['name.~1~']}, 'a', tt)
2345
 
        self.assertEqual('name.~2~', name2)
2346
 
 
2347
 
 
2348
2414
class TestFileMover(tests.TestCaseWithTransport):
2349
2415
 
2350
2416
    def test_file_mover(self):
2464
2530
        self.assertPathExists('a/b')
2465
2531
 
2466
2532
 
 
2533
class TestFinalizeRobustness(tests.TestCaseWithTransport):
 
2534
    """Ensure treetransform creation errors can be safely cleaned up after"""
 
2535
 
 
2536
    def _override_globals_in_method(self, instance, method_name, globals):
 
2537
        """Replace method on instance with one with updated globals"""
 
2538
        import types
 
2539
        func = getattr(instance, method_name).im_func
 
2540
        new_globals = dict(func.func_globals)
 
2541
        new_globals.update(globals)
 
2542
        new_func = types.FunctionType(func.func_code, new_globals,
 
2543
            func.func_name, func.func_defaults)
 
2544
        setattr(instance, method_name,
 
2545
            types.MethodType(new_func, instance, instance.__class__))
 
2546
        self.addCleanup(delattr, instance, method_name)
 
2547
 
 
2548
    @staticmethod
 
2549
    def _fake_open_raises_before(name, mode):
 
2550
        """Like open() but raises before doing anything"""
 
2551
        raise RuntimeError
 
2552
 
 
2553
    @staticmethod
 
2554
    def _fake_open_raises_after(name, mode):
 
2555
        """Like open() but raises after creating file without returning"""
 
2556
        open(name, mode).close()
 
2557
        raise RuntimeError
 
2558
 
 
2559
    def create_transform_and_root_trans_id(self):
 
2560
        """Setup a transform creating a file in limbo"""
 
2561
        tree = self.make_branch_and_tree('.')
 
2562
        tt = TreeTransform(tree)
 
2563
        return tt, tt.create_path("a", tt.root)
 
2564
 
 
2565
    def create_transform_and_subdir_trans_id(self):
 
2566
        """Setup a transform creating a directory containing a file in limbo"""
 
2567
        tree = self.make_branch_and_tree('.')
 
2568
        tt = TreeTransform(tree)
 
2569
        d_trans_id = tt.create_path("d", tt.root)
 
2570
        tt.create_directory(d_trans_id)
 
2571
        f_trans_id = tt.create_path("a", d_trans_id)
 
2572
        tt.adjust_path("a", d_trans_id, f_trans_id)
 
2573
        return tt, f_trans_id
 
2574
 
 
2575
    def test_root_create_file_open_raises_before_creation(self):
 
2576
        tt, trans_id = self.create_transform_and_root_trans_id()
 
2577
        self._override_globals_in_method(tt, "create_file",
 
2578
            {"open": self._fake_open_raises_before})
 
2579
        self.assertRaises(RuntimeError, tt.create_file, ["contents"], trans_id)
 
2580
        path = tt._limbo_name(trans_id)
 
2581
        self.assertPathDoesNotExist(path)
 
2582
        tt.finalize()
 
2583
        self.assertPathDoesNotExist(tt._limbodir)
 
2584
 
 
2585
    def test_root_create_file_open_raises_after_creation(self):
 
2586
        tt, trans_id = self.create_transform_and_root_trans_id()
 
2587
        self._override_globals_in_method(tt, "create_file",
 
2588
            {"open": self._fake_open_raises_after})
 
2589
        self.assertRaises(RuntimeError, tt.create_file, ["contents"], trans_id)
 
2590
        path = tt._limbo_name(trans_id)
 
2591
        self.assertPathExists(path)
 
2592
        tt.finalize()
 
2593
        self.assertPathDoesNotExist(path)
 
2594
        self.assertPathDoesNotExist(tt._limbodir)
 
2595
 
 
2596
    def test_subdir_create_file_open_raises_before_creation(self):
 
2597
        tt, trans_id = self.create_transform_and_subdir_trans_id()
 
2598
        self._override_globals_in_method(tt, "create_file",
 
2599
            {"open": self._fake_open_raises_before})
 
2600
        self.assertRaises(RuntimeError, tt.create_file, ["contents"], trans_id)
 
2601
        path = tt._limbo_name(trans_id)
 
2602
        self.assertPathDoesNotExist(path)
 
2603
        tt.finalize()
 
2604
        self.assertPathDoesNotExist(tt._limbodir)
 
2605
 
 
2606
    def test_subdir_create_file_open_raises_after_creation(self):
 
2607
        tt, trans_id = self.create_transform_and_subdir_trans_id()
 
2608
        self._override_globals_in_method(tt, "create_file",
 
2609
            {"open": self._fake_open_raises_after})
 
2610
        self.assertRaises(RuntimeError, tt.create_file, ["contents"], trans_id)
 
2611
        path = tt._limbo_name(trans_id)
 
2612
        self.assertPathExists(path)
 
2613
        tt.finalize()
 
2614
        self.assertPathDoesNotExist(path)
 
2615
        self.assertPathDoesNotExist(tt._limbodir)
 
2616
 
 
2617
    def test_rename_in_limbo_rename_raises_after_rename(self):
 
2618
        tt, trans_id = self.create_transform_and_root_trans_id()
 
2619
        parent1 = tt.new_directory('parent1', tt.root)
 
2620
        child1 = tt.new_file('child1', parent1, 'contents')
 
2621
        parent2 = tt.new_directory('parent2', tt.root)
 
2622
 
 
2623
        class FakeOSModule(object):
 
2624
            def rename(self, old, new):
 
2625
                os.rename(old, new)
 
2626
                raise RuntimeError
 
2627
        self._override_globals_in_method(tt, "_rename_in_limbo",
 
2628
            {"os": FakeOSModule()})
 
2629
        self.assertRaises(
 
2630
            RuntimeError, tt.adjust_path, "child1", parent2, child1)
 
2631
        path = osutils.pathjoin(tt._limbo_name(parent2), "child1")
 
2632
        self.assertPathExists(path)
 
2633
        tt.finalize()
 
2634
        self.assertPathDoesNotExist(path)
 
2635
        self.assertPathDoesNotExist(tt._limbodir)
 
2636
 
 
2637
    def test_rename_in_limbo_rename_raises_before_rename(self):
 
2638
        tt, trans_id = self.create_transform_and_root_trans_id()
 
2639
        parent1 = tt.new_directory('parent1', tt.root)
 
2640
        child1 = tt.new_file('child1', parent1, 'contents')
 
2641
        parent2 = tt.new_directory('parent2', tt.root)
 
2642
 
 
2643
        class FakeOSModule(object):
 
2644
            def rename(self, old, new):
 
2645
                raise RuntimeError
 
2646
        self._override_globals_in_method(tt, "_rename_in_limbo",
 
2647
            {"os": FakeOSModule()})
 
2648
        self.assertRaises(
 
2649
            RuntimeError, tt.adjust_path, "child1", parent2, child1)
 
2650
        path = osutils.pathjoin(tt._limbo_name(parent1), "child1")
 
2651
        self.assertPathExists(path)
 
2652
        tt.finalize()
 
2653
        self.assertPathDoesNotExist(path)
 
2654
        self.assertPathDoesNotExist(tt._limbodir)
 
2655
 
 
2656
 
2467
2657
class TestTransformMissingParent(tests.TestCaseWithTransport):
2468
2658
 
2469
2659
    def make_tt_with_versioned_dir(self):
2578
2768
 
2579
2769
    def test_iter_changes(self):
2580
2770
        revision_tree, preview_tree = self.get_tree_and_preview_tree()
2581
 
        root = revision_tree.inventory.root.file_id
 
2771
        root = revision_tree.get_root_id()
2582
2772
        self.assertEqual([('a-id', ('a', 'a'), True, (True, True),
2583
2773
                          (root, root), ('a', 'a'), ('file', 'file'),
2584
2774
                          (False, False))],
2588
2778
        revision_tree, preview_tree = self.get_tree_and_preview_tree()
2589
2779
        changes = preview_tree.iter_changes(revision_tree,
2590
2780
                                            include_unchanged=True)
2591
 
        root = revision_tree.inventory.root.file_id
 
2781
        root = revision_tree.get_root_id()
2592
2782
 
2593
2783
        self.assertEqual([ROOT_ENTRY, A_ENTRY], list(changes))
2594
2784
 
2651
2841
        preview_mtime = preview_tree.get_file_mtime('file-id', 'renamed')
2652
2842
        work_mtime = work_tree.get_file_mtime('file-id', 'file')
2653
2843
 
 
2844
    def test_get_file_size(self):
 
2845
        work_tree = self.make_branch_and_tree('tree')
 
2846
        self.build_tree_contents([('tree/old', 'old')])
 
2847
        work_tree.add('old', 'old-id')
 
2848
        preview = TransformPreview(work_tree)
 
2849
        self.addCleanup(preview.finalize)
 
2850
        new_id = preview.new_file('name', preview.root, 'contents', 'new-id',
 
2851
                                  'executable')
 
2852
        tree = preview.get_preview_tree()
 
2853
        self.assertEqual(len('old'), tree.get_file_size('old-id'))
 
2854
        self.assertEqual(len('contents'), tree.get_file_size('new-id'))
 
2855
 
2654
2856
    def test_get_file(self):
2655
2857
        preview = self.get_empty_preview()
2656
2858
        preview.new_file('file', preview.root, 'contents', 'file-id')
3068
3270
        merger.merge_type = Merge3Merger
3069
3271
        merger.do_merge()
3070
3272
 
 
3273
    def test_has_filename(self):
 
3274
        wt = self.make_branch_and_tree('tree')
 
3275
        self.build_tree(['tree/unmodified', 'tree/removed', 'tree/modified'])
 
3276
        tt = TransformPreview(wt)
 
3277
        removed_id = tt.trans_id_tree_path('removed')
 
3278
        tt.delete_contents(removed_id)
 
3279
        tt.new_file('new', tt.root, 'contents')
 
3280
        modified_id = tt.trans_id_tree_path('modified')
 
3281
        tt.delete_contents(modified_id)
 
3282
        tt.create_file('modified-contents', modified_id)
 
3283
        self.addCleanup(tt.finalize)
 
3284
        tree = tt.get_preview_tree()
 
3285
        self.assertTrue(tree.has_filename('unmodified'))
 
3286
        self.assertFalse(tree.has_filename('not-present'))
 
3287
        self.assertFalse(tree.has_filename('removed'))
 
3288
        self.assertTrue(tree.has_filename('new'))
 
3289
        self.assertTrue(tree.has_filename('modified'))
 
3290
 
3071
3291
    def test_is_executable(self):
3072
3292
        tree = self.make_branch_and_tree('tree')
3073
3293
        preview = TransformPreview(tree)
3096
3316
        self.assertEqual('contents', rev2_tree.get_file_text('file_id'))
3097
3317
 
3098
3318
    def test_ascii_limbo_paths(self):
3099
 
        self.requireFeature(tests.UnicodeFilenameFeature)
 
3319
        self.requireFeature(features.UnicodeFilenameFeature)
3100
3320
        branch = self.make_branch('any')
3101
3321
        tree = branch.repository.revision_tree(_mod_revision.NULL_REVISION)
3102
3322
        tt = TransformPreview(tree)
3119
3339
 
3120
3340
class TestSerializeTransform(tests.TestCaseWithTransport):
3121
3341
 
3122
 
    _test_needs_features = [tests.UnicodeFilenameFeature]
 
3342
    _test_needs_features = [features.UnicodeFilenameFeature]
3123
3343
 
3124
3344
    def get_preview(self, tree=None):
3125
3345
        if tree is None:
3200
3420
        return self.make_records(attribs, contents)
3201
3421
 
3202
3422
    def test_serialize_symlink_creation(self):
3203
 
        self.requireFeature(tests.SymlinkFeature)
 
3423
        self.requireFeature(features.SymlinkFeature)
3204
3424
        tt = self.get_preview()
3205
3425
        tt.new_symlink(u'foo\u1234', tt.root, u'bar\u1234')
3206
3426
        self.assertSerializesTo(self.symlink_creation_records(), tt)
3207
3427
 
3208
3428
    def test_deserialize_symlink_creation(self):
3209
 
        self.requireFeature(tests.SymlinkFeature)
 
3429
        self.requireFeature(features.SymlinkFeature)
3210
3430
        tt = self.get_preview()
3211
3431
        tt.deserialize(iter(self.symlink_creation_records()))
3212
3432
        abspath = tt._limbo_name('new-1')
3390
3610
        self.assertRaises(NotImplementedError, tt.new_orphan, 'foo', 'bar')
3391
3611
 
3392
3612
    def _set_orphan_policy(self, wt, policy):
3393
 
        wt.branch.get_config().set_user_option('bzr.transform.orphan_policy',
 
3613
        wt.branch.get_config_stack().set('bzr.transform.orphan_policy',
3394
3614
                                               policy)
3395
3615
 
3396
3616
    def _prepare_orphan(self, wt):
3469
3689
        self.assertEqual(('deleting parent', 'Not deleting', 'new-1'),
3470
3690
                         remaining_conflicts.pop())
3471
3691
        self.assertLength(1, warnings)
3472
 
        self.assertStartsWith(warnings[0], 'donttouchmypreciouuus')
 
3692
        self.assertStartsWith(warnings[0], 'Value "donttouchmypreciouuus" ')
 
3693
 
 
3694
 
 
3695
class TestTransformHooks(tests.TestCaseWithTransport):
 
3696
 
 
3697
    def setUp(self):
 
3698
        super(TestTransformHooks, self).setUp()
 
3699
        self.wt = self.make_branch_and_tree('.')
 
3700
        os.chdir('..')
 
3701
 
 
3702
    def get_transform(self):
 
3703
        transform = TreeTransform(self.wt)
 
3704
        self.addCleanup(transform.finalize)
 
3705
        return transform, transform.root
 
3706
 
 
3707
    def test_pre_commit_hooks(self):
 
3708
        calls = []
 
3709
        def record_pre_transform(tree, tt):
 
3710
            calls.append((tree, tt))
 
3711
        MutableTree.hooks.install_named_hook('pre_transform',
 
3712
            record_pre_transform, "Pre transform")
 
3713
        transform, root = self.get_transform()
 
3714
        old_root_id = transform.tree_file_id(root)
 
3715
        transform.apply()
 
3716
        self.assertEqual(old_root_id, self.wt.get_root_id())
 
3717
        self.assertEquals([(self.wt, transform)], calls)
 
3718
 
 
3719
    def test_post_commit_hooks(self):
 
3720
        calls = []
 
3721
        def record_post_transform(tree, tt):
 
3722
            calls.append((tree, tt))
 
3723
        MutableTree.hooks.install_named_hook('post_transform',
 
3724
            record_post_transform, "Post transform")
 
3725
        transform, root = self.get_transform()
 
3726
        old_root_id = transform.tree_file_id(root)
 
3727
        transform.apply()
 
3728
        self.assertEqual(old_root_id, self.wt.get_root_id())
 
3729
        self.assertEquals([(self.wt, transform)], calls)