summaryrefslogtreecommitdiff
path: root/bzrlib/tests/per_workingtree/test_paths2ids.py
diff options
context:
space:
mode:
Diffstat (limited to 'bzrlib/tests/per_workingtree/test_paths2ids.py')
-rw-r--r--bzrlib/tests/per_workingtree/test_paths2ids.py201
1 files changed, 201 insertions, 0 deletions
diff --git a/bzrlib/tests/per_workingtree/test_paths2ids.py b/bzrlib/tests/per_workingtree/test_paths2ids.py
new file mode 100644
index 0000000..1b19a5f
--- /dev/null
+++ b/bzrlib/tests/per_workingtree/test_paths2ids.py
@@ -0,0 +1,201 @@
+# Copyright (C) 2007 Canonical Ltd
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+"""Tests for WorkingTree.paths2ids.
+
+This API probably needs to be exposed as a tree implementation test, but these
+initial tests are for the specific cases being refactored from
+find_ids_across_trees.
+"""
+
+from operator import attrgetter
+
+from bzrlib import errors
+from bzrlib.tests import features
+from bzrlib.tests.per_workingtree import TestCaseWithWorkingTree
+
+
+# TODO: This needs an additional test: do a merge, then do a
+# paths2id(trees=left parent only), and also with (trees=all parents) to check
+# that only the requested trees are considered - i.e. have an unversioned path
+# in the unlisted tree, or an extra file that moves into the selected path but
+# should not be returned
+
+# TODO: test that supplying paths with duplication - i.e. foo, foo, foo/bar -
+# does not result in garbage out.
+
+# TODO: Are we meant to raise the precise unversioned paths when some are
+# unversioned - if so, test this.
+
+class TestPaths2Ids(TestCaseWithWorkingTree):
+
+ def assertExpectedIds(self, ids, tree, paths, trees=None,
+ require_versioned=True):
+ """Run paths2ids for tree, and check the result."""
+ tree.lock_read()
+ if trees:
+ map(apply, map(attrgetter('lock_read'), trees))
+ result = tree.paths2ids(paths, trees,
+ require_versioned=require_versioned)
+ map(apply, map(attrgetter('unlock'), trees))
+ else:
+ result = tree.paths2ids(paths,
+ require_versioned=require_versioned)
+ self.assertEqual(set(ids), result)
+ tree.unlock()
+
+ def test_paths_none_result_none(self):
+ tree = self.make_branch_and_tree('tree')
+ tree.lock_read()
+ self.assertEqual(None, tree.paths2ids(None))
+ tree.unlock()
+
+ def test_find_single_root(self):
+ tree = self.make_branch_and_tree('tree')
+ self.assertExpectedIds([tree.path2id('')], tree, [''])
+
+ def test_find_tree_and_clone_roots(self):
+ tree = self.make_branch_and_tree('tree')
+ clone = tree.bzrdir.clone('clone').open_workingtree()
+ clone.lock_tree_write()
+ clone_root_id = 'new-id'
+ clone.set_root_id(clone_root_id)
+ tree_root_id = tree.path2id('')
+ clone.unlock()
+ self.assertExpectedIds([tree_root_id, clone_root_id], tree, [''], [clone])
+
+ def test_find_tree_basis_roots(self):
+ tree = self.make_branch_and_tree('tree')
+ tree.commit('basis')
+ basis = tree.basis_tree()
+ basis_root_id = basis.path2id('')
+ tree.lock_tree_write()
+ tree_root_id = 'new-id'
+ tree.set_root_id(tree_root_id)
+ tree.unlock()
+ self.assertExpectedIds([tree_root_id, basis_root_id], tree, [''], [basis])
+
+ def test_find_children_of_moved_directories(self):
+ """Check the basic nasty corner case that path2ids should handle.
+
+ This is the following situation:
+ basis:
+ / ROOT
+ /dir dir
+ /dir/child-moves child-moves
+ /dir/child-stays child-stays
+ /dir/child-goes child-goes
+
+ current tree:
+ / ROOT
+ /child-moves child-moves
+ /newdir newdir
+ /newdir/dir dir
+ /newdir/dir/child-stays child-stays
+ /newdir/dir/new-child new-child
+
+ In english: we move a directory under a directory that was a sibling,
+ and at the same time remove, or move out of the directory, some of its
+ children, and give it a new child previous absent or a sibling.
+
+ current_tree.path2ids(['newdir'], [basis]) is meant to handle this
+ correctly: that is it should return the ids:
+ newdir because it was provided
+ dir, because its under newdir in current
+ child-moves because its under dir in old
+ child-stays either because its under newdir/dir in current, or under dir in old
+ child-goes because its under dir in old.
+ new-child because its under dir in new
+
+ Symmetrically, current_tree.path2ids(['dir'], [basis]) is meant to show
+ new-child, even though its not under the path 'dir' in current, because
+ its under a path selected by 'dir' in basis:
+ dir because its selected in basis.
+ child-moves because its under dir in old
+ child-stays either because its under newdir/dir in current, or under dir in old
+ child-goes because its under dir in old.
+ new-child because its under dir in new.
+ """
+ tree = self.make_branch_and_tree('tree')
+ self.build_tree(
+ ['tree/dir/', 'tree/dir/child-moves', 'tree/dir/child-stays',
+ 'tree/dir/child-goes'])
+ tree.add(['dir', 'dir/child-moves', 'dir/child-stays', 'dir/child-goes'],
+ ['dir', 'child-moves', 'child-stays', 'child-goes'])
+ tree.commit('create basis')
+ basis = tree.basis_tree()
+ tree.unversion(['child-goes'])
+ tree.rename_one('dir/child-moves', 'child-moves')
+ self.build_tree(['tree/newdir/'])
+ tree.add(['newdir'], ['newdir'])
+ tree.rename_one('dir/child-stays', 'child-stays')
+ tree.rename_one('dir', 'newdir/dir')
+ tree.rename_one('child-stays', 'newdir/dir/child-stays')
+ self.build_tree(['tree/newdir/dir/new-child'])
+ tree.add(['newdir/dir/new-child'], ['new-child'])
+ self.assertExpectedIds(
+ ['newdir', 'dir', 'child-moves', 'child-stays', 'child-goes',
+ 'new-child'], tree, ['newdir'], [basis])
+ self.assertExpectedIds(
+ ['dir', 'child-moves', 'child-stays', 'child-goes', 'new-child'],
+ tree, ['dir'], [basis])
+
+ def test_unversioned_one_tree(self):
+ tree = self.make_branch_and_tree('tree')
+ self.build_tree(['tree/unversioned'])
+ self.assertExpectedIds([], tree, ['unversioned'], require_versioned=False)
+ tree.lock_read()
+ self.assertRaises(errors.PathsNotVersionedError, tree.paths2ids, ['unversioned'])
+ tree.unlock()
+
+ def test_unversioned_in_one_of_multiple_trees(self):
+ # in this test, the path is unversioned in only one tree, and thus
+ # should not raise an error: it must be unversioned in *all* trees to
+ # error.
+ tree = self.make_branch_and_tree('tree')
+ tree.commit('make basis')
+ basis = tree.basis_tree()
+ self.build_tree(['tree/in-one'])
+ tree.add(['in-one'], ['in-one'])
+ self.assertExpectedIds(['in-one'], tree, ['in-one'], [basis])
+
+ def test_unversioned_all_of_multiple_trees(self):
+ # in this test, the path is unversioned in every tree, and thus
+ # should not raise an error: it must be unversioned in *all* trees to
+ # error.
+ tree = self.make_branch_and_tree('tree')
+ tree.commit('make basis')
+ basis = tree.basis_tree()
+ self.assertExpectedIds([], tree, ['unversioned'], [basis],
+ require_versioned=False)
+ tree.lock_read()
+ basis.lock_read()
+ self.assertRaises(errors.PathsNotVersionedError, tree.paths2ids,
+ ['unversioned'], [basis])
+ self.assertRaises(errors.PathsNotVersionedError, basis.paths2ids,
+ ['unversioned'], [tree])
+ basis.unlock()
+ tree.unlock()
+
+ def test_unversioned_non_ascii_one_tree(self):
+ self.requireFeature(features.UnicodeFilenameFeature)
+ tree = self.make_branch_and_tree('.')
+ self.build_tree([u"\xa7"])
+ self.assertExpectedIds([], tree, [u"\xa7"], require_versioned=False)
+ self.addCleanup(tree.lock_read().unlock)
+ e = self.assertRaises(errors.PathsNotVersionedError,
+ tree.paths2ids, [u"\xa7"])
+ self.assertEqual([u"\xa7"], e.paths)