Rev 2377: Alter intertree implementation tests to let dirstate inter-trees be correctly parameterised. in sftp://bazaar.launchpad.net/%7Ebzr/bzr/dirstate/

Robert Collins robertc at robertcollins.net
Fri Feb 23 05:13:26 GMT 2007


At sftp://bazaar.launchpad.net/%7Ebzr/bzr/dirstate/

------------------------------------------------------------
revno: 2377
revision-id: robertc at robertcollins.net-20070223051206-jqheguu2qeyqab14
parent: john at arbash-meinel.com-20070223030108-da1z3sofjti2xulz
committer: Robert Collins <robertc at robertcollins.net>
branch nick: dirstate
timestamp: Fri 2007-02-23 16:12:06 +1100
message:
  Alter intertree implementation tests to let dirstate inter-trees be correctly parameterised.
modified:
  bzrlib/tests/intertree_implementations/__init__.py __init__.py-20060724101752-09ysswo1a92uqyoz-3
  bzrlib/tests/intertree_implementations/test_compare.py test_compare.py-20060724101752-09ysswo1a92uqyoz-2
  bzrlib/tests/test_selftest.py  test_selftest.py-20051202044319-c110a115d8c0456a
  bzrlib/tests/test_workingtree_4.py test_workingtree_4.p-20070223025758-531n3tznl3zacv2o-1
  bzrlib/tree.py                 tree.py-20050309040759-9d5f2496be663e77
  bzrlib/workingtree_4.py        workingtree_4.py-20070208044105-5fgpc5j3ljlh5q6c-1
=== modified file 'bzrlib/tests/intertree_implementations/__init__.py'
--- a/bzrlib/tests/intertree_implementations/__init__.py	2006-10-11 23:08:27 +0000
+++ b/bzrlib/tests/intertree_implementations/__init__.py	2007-02-23 05:12:06 +0000
@@ -41,6 +41,11 @@
                                 )
 
 
+def return_provided_trees(source, target):
+    """Return the source and target tree unaltered."""
+    return source, target
+
+
 class TestCaseWithTwoTrees(TestCaseWithTree):
 
     def make_to_branch_and_tree(self, relpath):
@@ -51,27 +56,6 @@
         made_control.create_branch()
         return self.workingtree_format_to.initialize(made_control)
 
-    def get_to_tree_no_parents_no_content(self, empty_tree):
-        return super(TestCaseWithTwoTrees, self).get_tree_no_parents_no_content(empty_tree, converter=self.workingtree_to_test_tree_to)
-
-    def get_to_tree_no_parents_abc_content(self, empty_tree):
-        return super(TestCaseWithTwoTrees, self).get_tree_no_parents_abc_content(empty_tree, converter=self.workingtree_to_test_tree_to)
-
-    def get_to_tree_no_parents_abc_content_2(self, empty_tree):
-        return super(TestCaseWithTwoTrees, self).get_tree_no_parents_abc_content_2(empty_tree, converter=self.workingtree_to_test_tree_to)
-
-    def get_to_tree_no_parents_abc_content_3(self, empty_tree):
-        return super(TestCaseWithTwoTrees, self).get_tree_no_parents_abc_content_3(empty_tree, converter=self.workingtree_to_test_tree_to)
-
-    def get_to_tree_no_parents_abc_content_4(self, empty_tree):
-        return super(TestCaseWithTwoTrees, self).get_tree_no_parents_abc_content_4(empty_tree, converter=self.workingtree_to_test_tree_to)
-
-    def get_to_tree_no_parents_abc_content_5(self, empty_tree):
-        return super(TestCaseWithTwoTrees, self).get_tree_no_parents_abc_content_5(empty_tree, converter=self.workingtree_to_test_tree_to)
-
-    def get_to_tree_no_parents_abc_content_6(self, empty_tree):
-        return super(TestCaseWithTwoTrees, self).get_tree_no_parents_abc_content_6(empty_tree, converter=self.workingtree_to_test_tree_to)
-
 
 class InterTreeTestProviderAdapter(WorkingTreeTestProviderAdapter):
     """Generate test suites for each InterTree implementation in bzrlib."""
@@ -80,18 +64,21 @@
         result = TestSuite()
         for (intertree_class,
             workingtree_format,
-            workingtree_to_test_tree,
             workingtree_format_to,
-            workingtree_to_test_tree_to) in self._formats:
+            mutable_trees_to_test_trees) in self._formats:
             new_test = self._clone_test(
                 test,
                 workingtree_format._matchingbzrdir,
                 workingtree_format,
                 intertree_class.__name__)
             new_test.intertree_class = intertree_class
-            new_test.workingtree_to_test_tree = workingtree_to_test_tree
             new_test.workingtree_format_to = workingtree_format_to
-            new_test.workingtree_to_test_tree_to = workingtree_to_test_tree_to
+            # mutable_trees_to_test_trees takes two trees and converts them to
+            # whatever relationship the optimiser under test requires.
+            new_test.mutable_trees_to_test_trees = mutable_trees_to_test_trees
+            # workingtree_to_test_tree is set to disable changing individual
+            # trees: instead the mutable_trees_to_test_trees helper is used.
+            new_test.workingtree_to_test_tree = return_parameter
             result.addTest(new_test)
         return result
 
@@ -108,13 +95,14 @@
         ]
     test_intertree_permutations = [
         # test InterTree with two default-format working trees.
-        (InterTree, default_tree_format, return_parameter,
-         default_tree_format, return_parameter)]
+        (InterTree, default_tree_format, default_tree_format,
+         return_provided_trees)]
     for optimiser in InterTree._optimisers:
         test_intertree_permutations.append(
             (optimiser,
-             optimiser._matching_from_tree_format, optimiser._from_tree_converter,
-             optimiser._matching_to_tree_format, optimiser._to_tree_converter))
+             optimiser._matching_from_tree_format,
+             optimiser._matching_to_tree_format,
+             optimiser._test_mutable_trees_to_test_trees))
     adapter = InterTreeTestProviderAdapter(
         default_transport,
         # None here will cause a readonly decorator to be created

=== modified file 'bzrlib/tests/intertree_implementations/test_compare.py'
--- a/bzrlib/tests/intertree_implementations/test_compare.py	2007-02-23 01:36:02 +0000
+++ b/bzrlib/tests/intertree_implementations/test_compare.py	2007-02-23 05:12:06 +0000
@@ -28,7 +28,8 @@
         tree1 = self.make_branch_and_tree('1')
         tree2 = self.make_to_branch_and_tree('2')
         tree1 = self.get_tree_no_parents_no_content(tree1)
-        tree2 = self.get_to_tree_no_parents_no_content(tree2)
+        tree2 = self.get_tree_no_parents_no_content(tree2)
+        tree1, tree2 = self.mutable_trees_to_test_trees(tree1, tree2)
         d = self.intertree_class(tree1, tree2).compare()
         self.assertEqual([], d.added)
         self.assertEqual([], d.modified)
@@ -40,7 +41,8 @@
         tree1 = self.make_branch_and_tree('1')
         tree2 = self.make_to_branch_and_tree('2')
         tree1 = self.get_tree_no_parents_no_content(tree1)
-        tree2 = self.get_to_tree_no_parents_abc_content(tree2)
+        tree2 = self.get_tree_no_parents_abc_content(tree2)
+        tree1, tree2 = self.mutable_trees_to_test_trees(tree1, tree2)
         d = self.intertree_class(tree1, tree2).compare()
         self.assertEqual([('a', 'a-id', 'file'),
                           ('b', 'b-id', 'directory'),
@@ -52,14 +54,24 @@
         self.assertEqual([], d.unchanged)
 
     def test_dangling(self):
+        # This test depends on the ability for some trees to have a difference
+        # between a 'versioned present' and 'versioned not present' (aka
+        # dangling) file. In this test there are two trees each with a separate
+        # dangling file, and the dangling files should be considered absent for
+        # the test.
         tree1 = self.make_branch_and_tree('1')
-        tree2 = self.make_branch_and_tree('2')
+        tree2 = self.make_to_branch_and_tree('2')
         self.build_tree(['2/a'])
         tree2.add('a')
         os.unlink('2/a')
         self.build_tree(['1/b'])
         tree1.add('b')
         os.unlink('1/b')
+        # the conversion to test trees here will leave the trees intact for the
+        # default intertree, but may perform a commit for other tree types,
+        # which may reduce the validity of the test. XXX: Think about how to
+        # address this.
+        tree1, tree2 = self.mutable_trees_to_test_trees(tree1, tree2)
         d = self.intertree_class(tree1, tree2).compare()
         self.assertEqual([], d.added)
         self.assertEqual([], d.modified)
@@ -71,7 +83,8 @@
         tree1 = self.make_branch_and_tree('1')
         tree2 = self.make_to_branch_and_tree('2')
         tree1 = self.get_tree_no_parents_abc_content(tree1)
-        tree2 = self.get_to_tree_no_parents_no_content(tree2)
+        tree2 = self.get_tree_no_parents_no_content(tree2)
+        tree1, tree2 = self.mutable_trees_to_test_trees(tree1, tree2)
         d = self.intertree_class(tree1, tree2).compare()
         self.assertEqual([], d.added)
         self.assertEqual([], d.modified)
@@ -86,7 +99,8 @@
         tree1 = self.make_branch_and_tree('1')
         tree2 = self.make_to_branch_and_tree('2')
         tree1 = self.get_tree_no_parents_abc_content(tree1)
-        tree2 = self.get_to_tree_no_parents_abc_content_2(tree2)
+        tree2 = self.get_tree_no_parents_abc_content_2(tree2)
+        tree1, tree2 = self.mutable_trees_to_test_trees(tree1, tree2)
         d = self.intertree_class(tree1, tree2).compare()
         self.assertEqual([], d.added)
         self.assertEqual([('a', 'a-id', 'file', True, False)], d.modified)
@@ -98,7 +112,8 @@
         tree1 = self.make_branch_and_tree('1')
         tree2 = self.make_to_branch_and_tree('2')
         tree1 = self.get_tree_no_parents_abc_content(tree1)
-        tree2 = self.get_to_tree_no_parents_abc_content_3(tree2)
+        tree2 = self.get_tree_no_parents_abc_content_3(tree2)
+        tree1, tree2 = self.mutable_trees_to_test_trees(tree1, tree2)
         d = self.intertree_class(tree1, tree2).compare()
         self.assertEqual([], d.added)
         self.assertEqual([('b/c', 'c-id', 'file', False, True)], d.modified)
@@ -110,7 +125,8 @@
         tree1 = self.make_branch_and_tree('1')
         tree2 = self.make_to_branch_and_tree('2')
         tree1 = self.get_tree_no_parents_abc_content(tree1)
-        tree2 = self.get_to_tree_no_parents_abc_content_4(tree2)
+        tree2 = self.get_tree_no_parents_abc_content_4(tree2)
+        tree1, tree2 = self.mutable_trees_to_test_trees(tree1, tree2)
         d = self.intertree_class(tree1, tree2).compare()
         self.assertEqual([], d.added)
         self.assertEqual([], d.modified)
@@ -122,7 +138,8 @@
         tree1 = self.make_branch_and_tree('1')
         tree2 = self.make_to_branch_and_tree('2')
         tree1 = self.get_tree_no_parents_abc_content(tree1)
-        tree2 = self.get_to_tree_no_parents_abc_content_5(tree2)
+        tree2 = self.get_tree_no_parents_abc_content_5(tree2)
+        tree1, tree2 = self.mutable_trees_to_test_trees(tree1, tree2)
         d = self.intertree_class(tree1, tree2).compare()
         self.assertEqual([], d.added)
         self.assertEqual([], d.modified)
@@ -134,7 +151,8 @@
         tree1 = self.make_branch_and_tree('1')
         tree2 = self.make_to_branch_and_tree('2')
         tree1 = self.get_tree_no_parents_abc_content(tree1)
-        tree2 = self.get_to_tree_no_parents_abc_content_6(tree2)
+        tree2 = self.get_tree_no_parents_abc_content_6(tree2)
+        tree1, tree2 = self.mutable_trees_to_test_trees(tree1, tree2)
         d = self.intertree_class(tree1, tree2).compare()
         self.assertEqual([], d.added)
         self.assertEqual([], d.modified)
@@ -146,7 +164,8 @@
         tree1 = self.make_branch_and_tree('1')
         tree2 = self.make_to_branch_and_tree('2')
         tree1 = self.get_tree_no_parents_no_content(tree1)
-        tree2 = self.get_to_tree_no_parents_abc_content(tree2)
+        tree2 = self.get_tree_no_parents_abc_content(tree2)
+        tree1, tree2 = self.mutable_trees_to_test_trees(tree1, tree2)
         d = self.intertree_class(tree1, tree2).compare(specific_files=['a'])
         self.assertEqual([('a', 'a-id', 'file')], d.added)
         self.assertEqual([], d.modified)
@@ -158,7 +177,8 @@
         tree1 = self.make_branch_and_tree('1')
         tree2 = self.make_to_branch_and_tree('2')
         tree1 = self.get_tree_no_parents_no_content(tree1)
-        tree2 = self.get_to_tree_no_parents_abc_content(tree2)
+        tree2 = self.get_tree_no_parents_abc_content(tree2)
+        tree1, tree2 = self.mutable_trees_to_test_trees(tree1, tree2)
         d = self.intertree_class(tree1, tree2).compare(
             specific_files=['a', 'b/c'])
         self.assertEqual(
@@ -174,7 +194,8 @@
         tree1 = self.make_branch_and_tree('1')
         tree2 = self.make_to_branch_and_tree('2')
         tree1 = self.get_tree_no_parents_no_content(tree1)
-        tree2 = self.get_to_tree_no_parents_abc_content(tree2)
+        tree2 = self.get_tree_no_parents_abc_content(tree2)
+        tree1, tree2 = self.mutable_trees_to_test_trees(tree1, tree2)
         d = self.intertree_class(tree1, tree2).compare(specific_files=['b'])
         self.assertEqual(
             [('b', 'b-id', 'directory'),('b/c', 'c-id', 'file')],
@@ -189,7 +210,8 @@
         tree1 = self.make_branch_and_tree('1')
         tree2 = self.make_to_branch_and_tree('2')
         tree1 = self.get_tree_no_parents_abc_content(tree1)
-        tree2 = self.get_to_tree_no_parents_abc_content_5(tree2)
+        tree2 = self.get_tree_no_parents_abc_content_5(tree2)
+        tree1, tree2 = self.mutable_trees_to_test_trees(tree1, tree2)
         d = self.intertree_class(tree1, tree2).compare(want_unchanged=True)
         self.assertEqual([], d.added)
         self.assertEqual([], d.modified)
@@ -204,11 +226,17 @@
         tree1 = self.make_branch_and_tree('1')
         tree2 = self.make_to_branch_and_tree('2')
         tree1 = self.get_tree_no_parents_abc_content(tree1)
-        tree2 = self.get_to_tree_no_parents_abc_content_3(tree2)
+        tree2 = self.get_tree_no_parents_abc_content_3(tree2)
+        tree1, tree2 = self.mutable_trees_to_test_trees(tree1, tree2)
+        d = self.intertree_class(tree1, tree2).compare(specific_files=['b'])
         # the type of tree-3 does not matter - it is used as a lookup, not
-        # a dispatch
+        # a dispatch. XXX: For dirstate it does speak to the optimisability of
+        # the lookup, in merged trees it can be fast-pathed. We probably want
+        # two tests: one as is, and one with it as a pending merge.
         tree3 = self.make_branch_and_tree('3')
         tree3 = self.get_tree_no_parents_abc_content_6(tree3)
+        tree3.lock_read()
+        self.addCleanup(tree3.unlock)
         # tree 3 has 'e' which is 'c-id'. Tree 1 has c-id at b/c, and Tree 2
         # has c-id at b/c with its exec flag toggled.
         # without extra_trees, we should get no modifications from this
@@ -233,7 +261,8 @@
         tree1 = self.make_branch_and_tree('1')
         tree2 = self.make_to_branch_and_tree('2')
         tree1 = self.get_tree_no_parents_no_content(tree1)
-        tree2 = self.get_to_tree_no_parents_abc_content(tree2)
+        tree2 = self.get_tree_no_parents_abc_content(tree2)
+        tree1, tree2 = self.mutable_trees_to_test_trees(tree1, tree2)
         self.assertRaises(errors.PathsNotVersionedError, 
             self.intertree_class(tree1, tree2).compare,
             specific_files=['d'],
@@ -243,16 +272,30 @@
 class TestIterChanges(TestCaseWithTwoTrees):
     """Test the comparison iterator"""
 
+    def do_iter_changes(self, tree1, tree2, **extra_args):
+        """Helper to run _iter_changes from tree1 to tree2.
+        
+        :param tree1, tree2:  The source and target trees. These will be locked
+            automatically.
+        :param **extra_args: Extra args to pass to _iter_changes. This is not
+            inspected by this test helper.
+        """
+        tree1.lock_read()
+        tree2.lock_read()
+        try:
+            return list(self.intertree_class(tree1, tree2)
+                ._iter_changes(**extra_args))
+        finally:
+            tree1.unlock()
+            tree2.unlock()
+
     def test_compare_empty_trees(self):
         tree1 = self.make_branch_and_tree('1')
         tree2 = self.make_to_branch_and_tree('2')
         tree1 = self.get_tree_no_parents_no_content(tree1)
-        tree2 = self.get_to_tree_no_parents_no_content(tree2)
-        tree1.lock_read()
-        self.addCleanup(tree1.unlock)
-        tree2.lock_read()
-        self.addCleanup(tree2.unlock)
-        self.assertEqual([], list(tree2._iter_changes(tree1)))
+        tree2 = self.get_tree_no_parents_no_content(tree2)
+        tree1, tree2 = self.mutable_trees_to_test_trees(tree1, tree2)
+        self.assertEqual([], self.do_iter_changes(tree1, tree2))
 
     def added(self, tree, file_id):
         entry = tree.inventory[file_id]
@@ -272,150 +315,153 @@
         tree1 = self.make_branch_and_tree('1')
         tree2 = self.make_to_branch_and_tree('2')
         tree1 = self.get_tree_no_parents_no_content(tree1)
-        tree2 = self.get_to_tree_no_parents_abc_content(tree2)
-            
+        tree2 = self.get_tree_no_parents_abc_content(tree2)
+        tree1, tree2 = self.mutable_trees_to_test_trees(tree1, tree2)
         tree1.lock_read()
-        self.addCleanup(tree1.unlock)
         tree2.lock_read()
-        self.addCleanup(tree2.unlock)
-        self.assertEqual([self.added(tree2, 'root-id'),
-                          self.added(tree2, 'a-id'), 
-                          self.added(tree2, 'b-id'), 
-                          self.added(tree2, 'c-id'),
-                          self.deleted(tree1, 'empty-root-id')],
-                         list(tree2._iter_changes(tree1)))
+        expected_results = [
+            self.added(tree2, 'root-id'),
+            self.added(tree2, 'a-id'),
+            self.added(tree2, 'b-id'),
+            self.added(tree2, 'c-id'),
+            self.deleted(tree1, 'empty-root-id')]
+        tree1.unlock()
+        tree2.unlock()
+        self.assertEqual(expected_results, self.do_iter_changes(tree1, tree2))
 
     def test_empty_to_abc_content_a_only(self):
         tree1 = self.make_branch_and_tree('1')
         tree2 = self.make_to_branch_and_tree('2')
         tree1 = self.get_tree_no_parents_no_content(tree1)
-        tree2 = self.get_to_tree_no_parents_abc_content(tree2)
-        tree1.lock_read()
-        self.addCleanup(tree1.unlock)
-        tree2.lock_read()
-        self.addCleanup(tree2.unlock)
-        self.assertEqual([self.added(tree2, 'a-id')],
-                         list(tree2._iter_changes(tree1, 
-                                                 specific_file_ids=['a-id'])))
-        self.assertEqual([self.deleted(tree2, 'a-id')],
-                         list(tree1._iter_changes(tree2, 
-                                                 specific_file_ids=['a-id'])))
+        tree2 = self.get_tree_no_parents_abc_content(tree2)
+        tree1, tree2 = self.mutable_trees_to_test_trees(tree1, tree2)
+        tree1.lock_read()
+        tree2.lock_read()
+        self.assertEqual(
+            [self.added(tree2, 'a-id')],
+            self.do_iter_changes(tree1, tree2, specific_file_ids=['a-id']))
+        tree1.unlock()
+        tree2.unlock()
+
+    def test_abc_content_to_empty_to_abc_content_a_only(self):
+        tree1 = self.make_branch_and_tree('1')
+        tree2 = self.make_to_branch_and_tree('2')
+        tree1 = self.get_tree_no_parents_abc_content(tree1)
+        tree2 = self.get_tree_no_parents_no_content(tree2)
+        tree1, tree2 = self.mutable_trees_to_test_trees(tree1, tree2)
+        tree1.lock_read()
+        tree2.lock_read()
+        self.assertEqual(
+            [self.deleted(tree1, 'a-id')],
+            self.do_iter_changes(tree1, tree2, specific_file_ids=['a-id']))
+        tree1.unlock()
+        tree2.unlock()
 
     def test_empty_to_abc_content_a_and_c_only(self):
         tree1 = self.make_branch_and_tree('1')
         tree2 = self.make_to_branch_and_tree('2')
         tree1 = self.get_tree_no_parents_no_content(tree1)
-        tree2 = self.get_to_tree_no_parents_abc_content(tree2)
+        tree2 = self.get_tree_no_parents_abc_content(tree2)
+        tree1, tree2 = self.mutable_trees_to_test_trees(tree1, tree2)
         tree1.lock_read()
-        self.addCleanup(tree1.unlock)
         tree2.lock_read()
-        self.addCleanup(tree2.unlock)
-        self.assertEqual([self.added(tree2, 'a-id'),
-                          self.added(tree2, 'c-id')],
-                         list(tree2._iter_changes(tree1, 
-                                                 specific_file_ids=['a-id', 
-                                                                    'c-id'])))
-        d = self.intertree_class(tree1, tree2).compare(
-            specific_files=['a', 'b/c'])
+        expected_result = [self.added(tree2, 'a-id'), self.added(tree2, 'c-id')]
+        tree1.unlock()
+        tree2.unlock()
+        self.assertEqual(expected_result,
+            self.do_iter_changes(tree1, tree2, specific_file_ids=['a-id', 'c-id']))
 
-    def test_abc_content(self):
+    def test_abc_content_to_empty(self):
         tree1 = self.make_branch_and_tree('1')
         tree2 = self.make_to_branch_and_tree('2')
-        tree1 = self.get_tree_no_parents_no_content(tree1)
-        tree2 = self.get_to_tree_no_parents_abc_content(tree2)
+        tree1 = self.get_tree_no_parents_abc_content(tree1)
+        tree2 = self.get_tree_no_parents_no_content(tree2)
+        tree1, tree2 = self.mutable_trees_to_test_trees(tree1, tree2)
+        tree1.lock_read()
+        tree2.lock_read()
         def deleted(file_id):
-            entry = tree2.inventory[file_id]
-            path = tree2.id2path(file_id)
-            return (file_id, path, True, (True, False), 
+            entry = tree1.inventory[file_id]
+            path = tree1.id2path(file_id)
+            return (file_id, path, True, (True, False),
                     (entry.parent_id, None),
-                    (entry.name, None), (entry.kind, None), 
+                    (entry.name, None), (entry.kind, None),
                     (entry.executable, None))
-        tree1.lock_read()
-        self.addCleanup(tree1.unlock)
-        tree2.lock_read()
-        self.addCleanup(tree2.unlock)
-        self.assertEqual([self.added(tree1, 'empty-root-id'), 
-                          deleted('root-id'), deleted('a-id'), 
-                          deleted('b-id'), deleted('c-id')],
-                          list(tree1._iter_changes(tree2)))
+        expected_results = [self.added(tree2, 'empty-root-id'),
+                          deleted('root-id'), deleted('a-id'),
+                          deleted('b-id'), deleted('c-id')]
+        tree1.unlock()
+        tree2.unlock()
+        self.assertEqual(
+            expected_results,
+            self.do_iter_changes(tree1, tree2))
 
     def test_content_modification(self):
         tree1 = self.make_branch_and_tree('1')
         tree2 = self.make_to_branch_and_tree('2')
         tree1 = self.get_tree_no_parents_abc_content(tree1)
-        tree2 = self.get_to_tree_no_parents_abc_content_2(tree2)
-        root_id = tree1.inventory.root.file_id
-        tree1.lock_read()
-        self.addCleanup(tree1.unlock)
-        tree2.lock_read()
-        self.addCleanup(tree2.unlock)
-        self.assertEqual([('a-id', 'a', True, (True, True), 
-                          (root_id, root_id), ('a', 'a'), 
-                          ('file', 'file'), (False, False))], 
-                         list(tree2._iter_changes(tree1)))
+        tree2 = self.get_tree_no_parents_abc_content_2(tree2)
+        tree1, tree2 = self.mutable_trees_to_test_trees(tree1, tree2)
+        root_id = tree1.path2id('')
+        self.assertEqual([('a-id', 'a', True, (True, True),
+                          (root_id, root_id), ('a', 'a'),
+                          ('file', 'file'), (False, False))],
+                         self.do_iter_changes(tree1, tree2))
 
     def test_meta_modification(self):
         tree1 = self.make_branch_and_tree('1')
         tree2 = self.make_to_branch_and_tree('2')
         tree1 = self.get_tree_no_parents_abc_content(tree1)
-        tree2 = self.get_to_tree_no_parents_abc_content_3(tree2)
-        tree1.lock_read()
-        self.addCleanup(tree1.unlock)
-        tree2.lock_read()
-        self.addCleanup(tree2.unlock)
-        self.assertEqual([('c-id', 'b/c', False, (True, True), 
-                          ('b-id', 'b-id'), ('c', 'c'), ('file', 'file'), 
-                          (False, True))], list(tree2._iter_changes(tree1)))
+        tree2 = self.get_tree_no_parents_abc_content_3(tree2)
+        tree1, tree2 = self.mutable_trees_to_test_trees(tree1, tree2)
+        self.assertEqual([('c-id', 'b/c', False, (True, True),
+                          ('b-id', 'b-id'), ('c', 'c'), ('file', 'file'),
+                          (False, True))],
+                         self.do_iter_changes(tree1, tree2))
 
     def test_file_rename(self):
         tree1 = self.make_branch_and_tree('1')
         tree2 = self.make_to_branch_and_tree('2')
         tree1 = self.get_tree_no_parents_abc_content(tree1)
-        tree2 = self.get_to_tree_no_parents_abc_content_4(tree2)
-        root_id = tree1.inventory.root.file_id
-        tree1.lock_read()
-        self.addCleanup(tree1.unlock)
-        tree2.lock_read()
-        self.addCleanup(tree2.unlock)
-        self.assertEqual([('a-id', 'd', False, (True, True), 
+        tree2 = self.get_tree_no_parents_abc_content_4(tree2)
+        tree1, tree2 = self.mutable_trees_to_test_trees(tree1, tree2)
+        root_id = tree1.path2id('')
+        self.assertEqual([('a-id', 'd', False, (True, True),
                           (root_id, root_id), ('a', 'd'), ('file', 'file'),
-                          (False, False))], list(tree2._iter_changes(tree1)))
+                          (False, False))],
+                         self.do_iter_changes(tree1, tree2))
 
     def test_file_rename_and_modification(self):
         tree1 = self.make_branch_and_tree('1')
         tree2 = self.make_to_branch_and_tree('2')
         tree1 = self.get_tree_no_parents_abc_content(tree1)
-        tree2 = self.get_to_tree_no_parents_abc_content_5(tree2)
-        root_id = tree1.inventory.root.file_id
-        tree1.lock_read()
-        self.addCleanup(tree1.unlock)
-        tree2.lock_read()
-        self.addCleanup(tree2.unlock)
-        self.assertEqual([('a-id', 'd', True, (True, True), 
+        tree2 = self.get_tree_no_parents_abc_content_5(tree2)
+        tree1, tree2 = self.mutable_trees_to_test_trees(tree1, tree2)
+        root_id = tree1.path2id('')
+        self.assertEqual([('a-id', 'd', True, (True, True),
                           (root_id, root_id), ('a', 'd'), ('file', 'file'),
-                           (False, False))], list(tree2._iter_changes(tree1)))
+                           (False, False))],
+                         self.do_iter_changes(tree1, tree2))
 
     def test_file_rename_and_meta_modification(self):
         tree1 = self.make_branch_and_tree('1')
         tree2 = self.make_to_branch_and_tree('2')
         tree1 = self.get_tree_no_parents_abc_content(tree1)
-        tree2 = self.get_to_tree_no_parents_abc_content_6(tree2)
-        root_id = tree1.inventory.root.file_id
-        tree1.lock_read()
-        self.addCleanup(tree1.unlock)
-        tree2.lock_read()
-        self.addCleanup(tree2.unlock)
-        self.assertEqual([('c-id', 'e', False, (True, True), 
-                          ('b-id', root_id), ('c', 'e'), ('file', 'file'), 
-                          (False, True))], list(tree2._iter_changes(tree1)))
+        tree2 = self.get_tree_no_parents_abc_content_6(tree2)
+        tree1, tree2 = self.mutable_trees_to_test_trees(tree1, tree2)
+        root_id = tree1.path2id('')
+        self.assertEqual([('c-id', 'e', False, (True, True),
+                          ('b-id', root_id), ('c', 'e'), ('file', 'file'),
+                          (False, True))],
+                         self.do_iter_changes(tree1, tree2))
 
     def test_unchanged_with_renames_and_modifications(self):
         """want_unchanged should generate a list of unchanged entries."""
         tree1 = self.make_branch_and_tree('1')
         tree2 = self.make_to_branch_and_tree('2')
         tree1 = self.get_tree_no_parents_abc_content(tree1)
-        tree2 = self.get_to_tree_no_parents_abc_content_5(tree2)
-        root_id = tree1.inventory.root.file_id
+        tree2 = self.get_tree_no_parents_abc_content_5(tree2)
+        tree1, tree2 = self.mutable_trees_to_test_trees(tree1, tree2)
+        root_id = tree1.path2id('')
         tree1.lock_read()
         self.addCleanup(tree1.unlock)
         tree2.lock_read()
@@ -433,5 +479,4 @@
                           ('a-id', 'd', True, (True, True),
                           (root_id, root_id), ('a', 'd'), ('file', 'file'),
                           (False, False)), unchanged('c-id')],
-                         list(tree2._iter_changes(tree1,
-                                                 include_unchanged=True)))
+                         self.do_iter_changes(tree1, tree2, include_unchanged=True))

=== modified file 'bzrlib/tests/test_selftest.py'
--- a/bzrlib/tests/test_selftest.py	2007-02-17 03:34:50 +0000
+++ b/bzrlib/tests/test_selftest.py	2007-02-23 05:12:06 +0000
@@ -410,24 +410,24 @@
         server2 = "b"
         format1 = WorkingTreeFormat2()
         format2 = WorkingTreeFormat3()
-        formats = [(str, format1, format2, False, True),
-            (int, format2, format1, False, True)]
+        formats = [(str, format1, format2, "converter1"),
+            (int, format2, format1, "converter2")]
         adapter = InterTreeTestProviderAdapter(server1, server2, formats)
         suite = adapter.adapt(input_test)
         tests = list(iter(suite))
         self.assertEqual(2, len(tests))
         self.assertEqual(tests[0].intertree_class, formats[0][0])
         self.assertEqual(tests[0].workingtree_format, formats[0][1])
-        self.assertEqual(tests[0].workingtree_to_test_tree, formats[0][2])
-        self.assertEqual(tests[0].workingtree_format_to, formats[0][3])
-        self.assertEqual(tests[0].workingtree_to_test_tree_to, formats[0][4])
+        self.assertEqual(tests[0].workingtree_format_to, formats[0][2])
+        self.assertEqual(tests[0].mutable_trees_to_test_trees, formats[0][3])
+        self.assertEqual(tests[0].workingtree_to_test_tree, return_parameter)
         self.assertEqual(tests[0].transport_server, server1)
         self.assertEqual(tests[0].transport_readonly_server, server2)
         self.assertEqual(tests[1].intertree_class, formats[1][0])
         self.assertEqual(tests[1].workingtree_format, formats[1][1])
-        self.assertEqual(tests[1].workingtree_to_test_tree, formats[1][2])
-        self.assertEqual(tests[1].workingtree_format_to, formats[1][3])
-        self.assertEqual(tests[1].workingtree_to_test_tree_to, formats[1][4])
+        self.assertEqual(tests[1].workingtree_format_to, formats[1][2])
+        self.assertEqual(tests[1].mutable_trees_to_test_trees, formats[1][3])
+        self.assertEqual(tests[1].workingtree_to_test_tree, return_parameter)
         self.assertEqual(tests[1].transport_server, server1)
         self.assertEqual(tests[1].transport_readonly_server, server2)
 

=== modified file 'bzrlib/tests/test_workingtree_4.py'
--- a/bzrlib/tests/test_workingtree_4.py	2007-02-23 03:01:08 +0000
+++ b/bzrlib/tests/test_workingtree_4.py	2007-02-23 05:12:06 +0000
@@ -284,6 +284,19 @@
         lock_and_compare_all_current_dirstate(tree, 'lock_write')
         lock_and_compare_all_current_dirstate(tree, 'lock_write')
 
+    def test_constructing_invalid_interdirstate_raises(self):
+        tree = self.make_workingtree()
+        rev_id = tree.commit('first post')
+        rev_id2 = tree.commit('second post')
+        rev_tree = tree.branch.repository.revision_tree(rev_id)
+        # Exception is not a great thing to raise, but this test is 
+        # very short, and code is used to sanity check other tests, so 
+        # a full error object is YAGNI.
+        self.assertRaises(
+            Exception, workingtree_4.InterDirStateTree, rev_tree, tree)
+        self.assertRaises(
+            Exception, workingtree_4.InterDirStateTree, tree, rev_tree)
+
     def test_revtree_to_revtree_not_interdirstate(self):
         # we should not get a dirstate optimiser for two repository sourced
         # revtrees. we can't prove a negative, so we dont do exhaustive tests

=== modified file 'bzrlib/tree.py'
--- a/bzrlib/tree.py	2007-02-22 15:04:35 +0000
+++ b/bzrlib/tree.py	2007-02-23 05:12:06 +0000
@@ -87,10 +87,10 @@
             include_root=include_root
             )
 
-    def _iter_changes(self, from_tree, include_unchanged=False, 
+    def _iter_changes(self, from_tree, include_unchanged=False,
                      specific_file_ids=None, pb=None):
         intertree = InterTree.get(from_tree, self)
-        return intertree._iter_changes(from_tree, self, include_unchanged, 
+        return intertree._iter_changes(include_unchanged,
                                        specific_file_ids, pb)
     
     def conflicts(self):
@@ -587,28 +587,29 @@
         return delta._compare_trees(self.source, self.target, want_unchanged,
             specific_file_ids, include_root)
 
-    def _iter_changes(self, from_tree, to_tree, include_unchanged, 
-                      specific_file_ids, pb):
+    def _iter_changes(self, include_unchanged=False,
+                      specific_file_ids=None, pb=None):
         """Generate an iterator of changes between trees.
 
         A tuple is returned:
         (file_id, path, changed_content, versioned, parent, name, kind,
          executable)
 
-        Path is relative to the to_tree.  changed_content is True if the file's
-        content has changed.  This includes changes to its kind, and to
+        Path is relative to the target tree.  changed_content is True if the
+        file's content has changed.  This includes changes to its kind, and to
         a symlink's target.
 
         versioned, parent, name, kind, executable are tuples of (from, to).
         If a file is missing in a tree, its kind is None.
 
-        Iteration is done in parent-to-child order, relative to the to_tree.
+        Iteration is done in parent-to-child order, relative to the target
+        tree.
         """
         to_paths = {}
-        from_entries_by_dir = list(from_tree.inventory.iter_entries_by_dir(
+        from_entries_by_dir = list(self.source.inventory.iter_entries_by_dir(
             specific_file_ids=specific_file_ids))
         from_data = dict((e.file_id, (p, e)) for p, e in from_entries_by_dir)
-        to_entries_by_dir = list(to_tree.inventory.iter_entries_by_dir(
+        to_entries_by_dir = list(self.target.inventory.iter_entries_by_dir(
             specific_file_ids=specific_file_ids))
         num_entries = len(from_entries_by_dir) + len(to_entries_by_dir)
         entry_count = 0
@@ -624,7 +625,7 @@
                 from_name = from_entry.name
                 from_parent = from_entry.parent_id
                 from_kind, from_executable, from_stat = \
-                    from_tree._comparison_data(from_entry, from_path)
+                    self.source._comparison_data(from_entry, from_path)
                 entry_count += 1
             else:
                 from_versioned = False
@@ -634,21 +635,21 @@
                 from_executable = None
             versioned = (from_versioned, True)
             to_kind, to_executable, to_stat = \
-                to_tree._comparison_data(to_entry, to_path)
+                self.target._comparison_data(to_entry, to_path)
             kind = (from_kind, to_kind)
             if kind[0] != kind[1]:
                 changed_content = True
             elif from_kind == 'file':
-                from_size = from_tree._file_size(from_entry, from_stat)
-                to_size = to_tree._file_size(to_entry, to_stat)
+                from_size = self.source._file_size(from_entry, from_stat)
+                to_size = self.target._file_size(to_entry, to_stat)
                 if from_size != to_size:
                     changed_content = True
-                elif (from_tree.get_file_sha1(file_id, from_path, from_stat) !=
-                    to_tree.get_file_sha1(file_id, to_path, to_stat)):
+                elif (self.source.get_file_sha1(file_id, from_path, from_stat) !=
+                    self.target.get_file_sha1(file_id, to_path, to_stat)):
                     changed_content = True
             elif from_kind == 'symlink':
-                if (from_tree.get_symlink_target(file_id) != 
-                    to_tree.get_symlink_target(file_id)):
+                if (self.source.get_symlink_target(file_id) != 
+                    self.target.get_symlink_target(file_id)):
                     changed_content = True
             parent = (from_parent, to_entry.parent_id)
             name = (from_name, to_entry.name)
@@ -666,7 +667,7 @@
                 to_path = ''
             else:
                 if from_entry.parent_id not in to_paths:
-                    get_to_path(from_tree.inventory[from_entry.parent_id])
+                    get_to_path(self.source.inventory[from_entry.parent_id])
                 to_path = osutils.pathjoin(to_paths[from_entry.parent_id],
                                            from_entry.name)
             to_paths[from_entry.file_id] = to_path
@@ -684,7 +685,7 @@
             parent = (from_entry.parent_id, None)
             name = (from_entry.name, None)
             from_kind, from_executable, stat_value = \
-                from_tree._comparison_data(from_entry, path)
+                self.source._comparison_data(from_entry, path)
             kind = (from_kind, None)
             executable = (from_executable, None)
             changed_content = True

=== modified file 'bzrlib/workingtree_4.py'
--- a/bzrlib/workingtree_4.py	2007-02-23 02:50:58 +0000
+++ b/bzrlib/workingtree_4.py	2007-02-23 05:12:06 +0000
@@ -1235,15 +1235,55 @@
 class InterDirStateTree(InterTree):
     """Fast path optimiser for changes_from with dirstate trees."""
 
+    def __init__(self, source, target):
+        super(InterDirStateTree, self).__init__(source, target)
+        if not InterDirStateTree.is_compatible(source, target):
+            raise Exception, "invalid source %r and target %r" % (source, target)
+
     @staticmethod
-    def revision_tree_from_workingtree(tree):
-        """Create a revision tree from a working tree."""
-        revid = tree.commit('save tree', allow_pointless=True)
-        return tree.branch.repository.revision_tree(revid)
-    _from_tree_converter = revision_tree_from_workingtree
+    def make_source_parent_tree(source, target):
+        """Change the source tree into a parent of the target."""
+        revid = source.commit('record tree')
+        target.branch.repository.fetch(source.branch.repository, revid)
+        target.set_parent_ids([revid])
+        return target.basis_tree(), target
     _matching_from_tree_format = WorkingTreeFormat4()
     _matching_to_tree_format = WorkingTreeFormat4()
-    _to_tree_converter = staticmethod(lambda x: x)
+    _test_mutable_trees_to_test_trees = make_source_parent_tree
+
+    @needs_read_lock
+    def compare(self, want_unchanged=False, specific_files=None,
+        extra_trees=None, require_versioned=False, include_root=False):
+        """Return the changes from source to target.
+
+        :return: A TreeDelta.
+        :param specific_files: An optional list of file paths to restrict the
+            comparison to. When mapping filenames to ids, all matches in all
+            trees (including optional extra_trees) are used, and all children of
+            matched directories are included.
+        :param want_unchanged: An optional boolean requesting the inclusion of
+            unchanged entries in the result.
+        :param extra_trees: An optional list of additional trees to use when
+            mapping the contents of specific_files (paths) to file_ids.
+        :param require_versioned: An optional boolean (defaults to False). When
+            supplied and True all the 'specific_files' must be versioned, or
+            a PathsNotVersionedError will be thrown.
+        """
+        # NB: show_status depends on being able to pass in non-versioned files
+        # and report them as unknown
+        trees = (self.source,)
+        if extra_trees is not None:
+            trees = trees + tuple(extra_trees)
+        # target is usually the newer tree:
+        specific_file_ids = self.target.paths2ids(specific_files, trees,
+            require_versioned=require_versioned)
+        from bzrlib import delta
+        if specific_files and not specific_file_ids:
+            # All files are unversioned, so just return an empty delta
+            # _compare_trees would think we want a complete delta
+            return delta.TreeDelta()
+        return delta._compare_trees(self.source, self.target, want_unchanged,
+            specific_file_ids, include_root)
 
     @staticmethod
     def is_compatible(source, target):



More information about the bazaar-commits mailing list